Dev server (Turbopack): all child routes below a dynamic segment inside route groups intermittently 404 for an entire next dev session; any file event under app/ repairs the router
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 142k
- Forks
- 32.4k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 351
Description
Link to the code that reproduces this issue
https://github.com/arpi09/next-dev-router-group-race
To Reproduce
git clone https://github.com/arpi09/next-dev-router-group-race
cd next-dev-router-group-race
npm install
node scripts/cpu-load.mjs 4 30 # optional: CPU load raises the hit rate
node scripts/boot-loop.mjs 10
The script boots next dev repeatedly and requests /fam1/a/child (a page that exists: app/(g1)/(g2)/fam1/[slug]/child/page.js with generateStaticParams returning {slug:'a'}). Each boot is classified:
- AFFECTED: the request answers 404 and the dev log never prints
Compiling /fam1/[slug]/child, i.e. the router never matched an existing page. The state then persists for the whole session. - HEALTHY: the route compiles and answers 200.
Example from the machine where this was found (Windows 11, 14 cores):
boot 8/8: AFFECTED
result: 1/8 boots AFFECTED
Honest expectation management: the synthetic repro's hit rate is low on my machine (one AFFECTED boot across ~30 loop boots so far), while the ~120-route production app where the bug was discovered is affected on roughly half of all boots when the machine is under load, and it reproduces there daily. I could not find the exact ingredient that makes the production app so much more susceptible; the diagnostic signature below (instant 404 with no "Compiling" line, whole-class scope, repair by any file event) should hopefully let someone who knows the route-tree construction code locate the race regardless.
Manual verification of one affected boot:
npx next dev -p 4321curl -i http://localhost:4321/fam1/a/child-> instant 404, no "Compiling /fam1/[slug]/child" line in the logcurl -i http://localhost:4321/fam1/a-> 200 (the dynamic leaf itself matches fine)- Append a blank line to any
app/**/page.js, save, remove it, save again curl -i http://localhost:4321/fam1/a/child-> now compiles and answers 200
Current vs. Expected behavior
Current: on an affected boot, every route of the class (route-group)/…/[dynamic]/<child> (pages and route handlers alike, across all route groups) returns an instant 404 without compiling, for the entire lifetime of the dev server. The [dynamic] leaf page itself matches and renders, identical structures outside route groups are never affected, and next build + next start always serve everything.
Expected: next dev matches the same routes on every boot that the production build serves.
Provide environment information
Operating System:
Platform: win32
Arch: x64
Version: Windows 11 Pro
Available memory (MB): 32282
Available CPU cores: 14
Binaries:
Node: 24.19.0
npm: 11.17.0
Relevant Packages:
next: 16.3.1 (also reproduced on 16.3.2 and 16.4.0-canary.7, see below)
react: 19.2.8
react-dom: 19.2.8
typescript: 6.0.3
Next.js Config:
output: N/A (dev; production builds use standalone)
Which area(s) are affected? (leave empty if unsure)
Turbopack, Dynamic Routes (dev server route matching)
Which stage(s) are affected? (leave empty if unsure)
next dev (local)
Additional context
This is a refiling of #97894 and #97896, which were auto-closed by the reproduction-link check (the first had no repo link yet; the second had extra prose in the link section). The reproduction repo is public and linked above. The bug is a per-boot race, so the repro is probabilistic: the repo ships a boot-loop script that classifies each boot from the dev log.
Any file event under app/ repairs the router for the rest of the session, including for families that were never touched: appending a newline to one page.tsx and restoring the original content 500 ms later makes every 404ing family match again (verified repeatedly, also long into a session). This is what points at a race in route-tree construction rather than at persisted state.
Timing matters: a file event fired ~1.5 s after "Ready" is swallowed (the class keeps 404ing); the same edit fired later repairs it. Our production workaround wraps next dev and touches a page file at ready+5/20/60 s, which has made every boot healthy so far.
Ruled out empirically in the production app. Each of these appeared to fix the problem exactly once, because every restart re-rolls the dice; longer series showed they change nothing:
- deleting
.next/devbefore boot (fully fresh-cache boots are affected too) - deleting only
.next/dev/server experimental.turbopackFileSystemCacheForDev: false- upgrading 16.3.0 -> 16.3.1 -> 16.3.2
Confirmed on 16.4.0-canary.7: an affected boot instantly 404s the class (no "Compiling" line; a later long-timeout request completed as GET ... 404 in 45s (next.js: 43s ...) with the route still never compiled), then a single file touch made the same URL compile and return 200.
The affected pages export dynamicParams = false and generateStaticParams (both parent and child); I have not isolated whether those exports are required or incidental. The reproduction did not trigger in a near-empty app; module-graph weight (the repo uses a 1.5 MB shared module and ~330 routes) appears to matter.
Log excerpts from the production app. Affected boot (no Compiling line, router never matched):
GET /vardcentral/abrahamsbergs-vardcentral/ring 404 in 210ms (next.js: 79ms, application-code: 131ms)
Healthy boot, same request:
○ Compiling /vardcentral/[slug]/ring ...
GET /vardcentral/abrahamsbergs-vardcentral/ring 200 in 21.8s
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with scripts/boot-loop.mjs and the route app/(g1)/(g2)/fam1/[slug]/child/page.js in the linked reproduction, then inspect Next.js dev route-tree construction for the affected dynamic child routes. Run next dev under repeated boots and compare the instant 404 with the later file-event repair. Done means the route consistently compiles and returns 200 without touching app files.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nextjs
- Domain
- backend, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100