Skip to content

App Router: Flight decode can execute incompatible modules before build mismatch recovery during rolling deploy #90622

@wa3l

Description

@wa3l

Link to the code that reproduces this issue

https://github.com/wa3l/nextjs-version-skew-repro

To Reproduce

  1. Clone the repro repo.
  2. Install dependencies.
  3. Run: ./scripts/reproduce.sh
  4. Open http://localhost:3000 immediately.
  5. In DevTools Console, enable Preserve log.
    Image
  6. Wait for the deploy message (~10s).
  7. Click Other Page.
    Observed in console (example):
  • Uncaught TypeError: (0 , n.tripleCount) is not a function
  • thrown at module evaluation in a client chunk
  • in some runs/environments: ChunkLoadError

Current vs. Expected behavior

Current behavior (unpatched):
During rolling-deploy skew (Build A runtime in browser, Build B RSC/navigation response from server), the client can execute incompatible modules/chunks before mismatch recovery and hit fatal runtime errors (TypeError / ChunkLoadError).

Expected behavior:
Build mismatch should be detected before Flight decode/evaluation of incompatible modules, so the client can hard reload first and avoid fatal runtime breakage.

Provide environment information

Operating System: macOS (darwin 25.3.0)
Node.js: 20+
next: 16.1.5
react: 19.x
react-dom: 19.x

Which area(s) are affected? (Select all that apply)

Module Resolution

Which stage(s) are affected? (Select all that apply)

Other (Deployed)

Additional context

This appears to be an ordering problem in fetch-server-response during rolling deploy skew.

What skew means in this report

  • Browser has already booted with Build A JS runtime and module registry in memory.
  • A client-side navigation request is routed to a server now running Build B.
  • The RSC/Flight payload references Build B modules/chunks.

Why this fails today

In fetch-server-response, decode can start in createFetch via createFromNextFetch(...) before the build mismatch check (flightResponse.b) is evaluated later in fetchServerResponse.

So there is a window where Build B module references are being decoded/resolved/evaluated inside a Build A-initialized runtime. That can produce:

  • missing or incompatible export shape (TypeError: ... is not a function)
  • chunk failures (ChunkLoadError) depending on asset mapping and cache/CDN behavior
  • other runtime binding/context mismatches

What this repro intentionally proves

The repro intentionally creates deterministic A->B skew and forces one incompatible module path:

  • ./scripts/reproduce.sh (unpatched): demonstrates fatal runtime break in browser before safe recovery.
  • ./scripts/reproduce-fixed.sh (patched demo): same scenario, but with an early header check that forces hard reload before decode executes incompatible modules.

This is why the patched demo logs:

  • [version-skew-fix] Early build mismatch detected; forcing hard reload

and avoids the fatal tripleCount is not a function crash.

Proposed fix direction

Make build identity available before decode (e.g. x-build-id response header) and check it before creating/awaiting Flight decode for navigation responses.

If mismatch:

  • skip decode path
  • trigger hard navigation/reload immediately

Metadata

Metadata

Assignees

No one assigned

    Labels

    Module ResolutionModule resolution (CJS / ESM, module resolving).

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions