Skip to content

v4: auth0.middleware() crashes with "Cannot read properties of undefined (reading 'provider')" when invoked from proxy.ts under Next.js 16 (works from a Route Handler) #2781

Description

@VACTR

Checklist

Description

auth0.middleware() throws TypeError: Cannot read properties of undefined (reading 'provider') on every request when invoked from proxy.ts under Next.js 16. Reproduced identically in both next dev and next start (production build) — not a dev-only artifact.

The most diagnostic detail: the identical auth0.middleware() call succeeds when dispatched from a Route Handler and fails when dispatched from proxy.ts. Same Auth0Client instance, same request, two different call sites:

  • GET /api/auth/login (dispatched from app/api/auth/[auth0]/route.ts, calling auth0.middleware(req) directly inside a GET handler) → works correctly. Clean 307 to the real Auth0 /authorize endpoint with correct client_id, PKCE code_challenge, state, nonce, and a properly-set transaction cookie.
  • GET /login (an ordinary app page, covered by proxy.ts's matcher) → crashes with the trace below, on every request, no exceptions.

I initially suspected this might be an Edge-vs-Node runtime difference, since the working call site is a Node.js Route Handler. I tested this directly by adding export const runtime = "nodejs" to proxy.ts — Next.js rejected it outright at build time: Error: Route segment config is not allowed in Proxy file... Proxy always runs on Node.js runtime. So there is no Edge/Node distinction to invoke here; proxy.ts is already Node-only under Next 16, and the crash happens anyway. I was not able to narrow the root cause further than that structural contrast.

Also ruled out: fake/placeholder Auth0 credentials (re-tested against a real, valid Auth0 tenant and real client credentials — identical crash); an SDK version predating Next 16 support (this is reproduced on 4.25.0, whose own peerDependencies list next: "... || ^16.0.10"); the SDK's env-var-lazy domain resolver (passed domain explicitly instead of relying on the AUTH0_DOMAIN fallback — identical crash).

Workaround in use: removed proxy.ts entirely. Route mounting still works via the Route Handler (route.ts), and route protection is handled by each protected layout calling auth0.getSession() directly rather than relying on the proxy. The only capability lost is automatic rolling-session refresh.

Reproduction

  1. Create a Next.js 16 app (App Router, Turbopack): npx create-next-app@latest --typescript
  2. Add @auth0/nextjs-auth0 (4.25.0) and configure a minimal Auth0Client in e.g. auth.ts:
    import { Auth0Client } from "@auth0/nextjs-auth0/server";
    export const auth0 = new Auth0Client();
  3. Create proxy.ts at the project root per the v4 migration guide's Next 16 section:
    import { auth0 } from "./auth";
    export default auth0.middleware;
    export const config = {
      matcher: ["/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)"],
    };
  4. Set real (or placeholder — both reproduce it) AUTH0_DOMAIN, AUTH0_CLIENT_ID, AUTH0_CLIENT_SECRET, AUTH0_SECRET, AUTH0_BASE_URL env vars.
  5. next build && next start, then request any page not excluded by the matcher (e.g. /).
  6. Expect: normal page response. Actual: 500, with the trace below in the server log.

Additional context

Full trace (paths are the local build output; the specific file/hash naturally varies by build):

TypeError: Cannot read properties of undefined (reading 'provider')
    at middleware (.next\server\chunks\[root-of-the-server]__<hash>._.js:31:138428)
    at handler (.next\server\chunks\[root-of-the-server]__<hash>._.js:34:1616)
    at <unknown> (.next\server\chunks\[root-of-the-server]__<hash>._.js:15:37004)
    at <unknown> (.next\server\chunks\[root-of-the-server]__<hash>._.js:15:36970)
    at async t2 (.next\server\chunks\[root-of-the-server]__<hash>._.js:15:33484)

Looking at dist/server/client.js (~line 195–243), the constructor's own comments describe an initialization-order dependency: this.provider is assigned via new AuthClientProvider(...), and a factory closure captures this by reference intending to read this.provider only after that assignment completes, with an explicit static-mode workaround for the case where "the factory ... is called during AuthClientProvider construction, before this.provider is fully assigned." That reads like the class of race the crash matches, but I wasn't able to confirm it's the same code path triggering under the proxy specifically.

nextjs-auth0 version

4.25.0 (also reproduced on 4.22.0 before upgrading)

Next.js version

16.2.12 (Turbopack)

Node.js version

24.14.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions