next dev hangs forever (no error, no overlay) when a module request exceeds ~8.39M chars — bundled enhanced-resolve predates the non-regex fast path
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/MuzajsArcin/nextjs-dev-hang-repro
To Reproduce
- git clone https://github.com/MuzajsArcin/nextjs-dev-hang-repro
- cd nextjs-dev-hang-repro && npm install
- node generate.mjs # writes src/big.mjs — one 13,280,481-char data: URI
- npm run dev # webpack dev server
- curl --max-time 60 http://localhost:3247/ -> never responds
Pages Router, empty next.config.mjs, no custom webpack config. src/big.mjs is a single line:
export const wasmUrl = new URL("data:application/wasm;base64,AAAA…", import.meta.url).href;
The size boundary is the clearest signal — same input, one character apart:
node generate.mjs 8388572 && npm run dev # HTTP 500, ordinary error overlay
node generate.mjs 8388573 && npm run dev # hangs forever
Turbopack is unaffected: npm run dev:turbo returns HTTP 200 in ~1s.
Current vs. Expected behavior
Current: compilation never finishes and the request never resolves. curl exits 28; the browser spins indefinitely. The dev server prints only:
○ Compiling / ...
RangeError: Maximum call stack size exceeded
at RegExp.exec (<anonymous>)
⨯ unhandledRejection: RangeError: Maximum call stack size exceeded
at RegExp.exec (<anonymous>)
Expected: either it compiles (Turbopack does, in ~1s), or it fails with an error overlay naming the module. A RangeError during compilation should not leave the request permanently unresolved.
Two things make this unusually expensive to debug:
- The single
at RegExp.execframe is not a truncated trace — the overflow happens inside V8's regexp engine, so no JS frame points at the offending module.--stack-trace-limitdoes not help, and neither does--stack-size(tried up to 60 MB): this is V8's RegExp stack cap, not the JS call stack. - Because it surfaces as
unhandledRejectionrather than a compilation error, there is no overlay, no failed build and no module path — just an infinite hang.
I located it by preloading a patched RegExp.prototype.exec via NODE_OPTIONS --require and logging this.source plus a fresh new Error().stack from inside the catch (the regexp frames have unwound by then, so the caller chain is visible).
Root cause
parseIdentifier in the bundled enhanced-resolve runs PATH_QUERY_FRAGMENT_REGEXP on every module request. V8 throws RangeError once the subject exceeds its RegExp stack limit. Bisected to the character on Node 22.23.2 / V8 12.4.254.21-node.56: the largest input that still succeeds is 8,388,572 characters — 36 below 2^23 — identical for "A".repeat(n) and for a data: URI of the same length.
This is already fixed in enhanced-resolve itself. Standalone 5.22.0 skips the regex unless the identifier actually contains \0:
const firstEscape = identifier.indexOf("\0");
if (firstEscape !== -1) { /* regex path */ }
// otherwise: linear indexOf scans, no regex at all
But next/dist/compiled/webpack/bundle5.js still carries the older version:
const I=/^(#?(?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
function parseIdentifier(v){const P=I.exec(v); ... }
(No firstEscape, no dosPrefixEnd — confirmed by string-searching the bundle.)
Driving webpack 5.107.2 + enhanced-resolve 5.22.0 through the Node API over the identical generated module: 0 errors, build completes. So plain webpack is fine; only the vendored copy is affected.
Suggested fixes
- Refresh the bundled
enhanced-resolveinnext/dist/compiled/webpackto a version with the\0fast path. This alone removes the failure. - Do not let a compiler
RangeErrorbecome an infinite hang. Even after (1), any futureunhandledRejectioninside compilation should reject the pending request with an error overlay rather than leaving it open forever. That is the part that cost the most debugging time.
Where this came from (not synthetic)
@mlightcad/cad-simple-viewer ships an Emscripten SINGLE_FILE=1 worker (dist/libredwg-parser-worker.js) with a ~10 MB .wasm inlined as new URL("data:application/wasm;base64,…", import.meta.url). Any Next.js app that pulls that package into a route's module graph loses webpack dev for that route entirely. In our app three route families died at once while next build stayed green, which made it look like an app bug rather than a toolchain one. Reported to that package as well: https://github.com/mlightcad/cad-viewer/issues/494
Note
Still reproduces on next@canary 16.3.1-canary.16 (run with --webpack, since Turbopack is the dev default in 16). Turbopack is unaffected in both dev and build, on 15 and on canary.
Earlier attempts #97364 and #97365 were auto-closed by the bot because I filed them through the gh CLI rather than this form, so the reproduction link was not detected. Same report, now filed properly.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.6.0
Available memory (MB): 24576
Available CPU cores: 10
Binaries:
Node: 22.23.2
npm: 10.9.8
Yarn: N/A
pnpm: 11.10.0
Relevant Packages:
next: 15.5.18 (also reproduced on 16.3.1-canary.16 with --webpack)
eslint-config-next: N/A
react: 18.3.1
react-dom: 18.3.1
typescript: N/A
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Webpack
Which stage(s) are affected? (Select all that apply)
next dev (local)
Additional context
Reproduces locally on macOS 26.6.1 (arm64), Node 22.23.2. Not platform-specific as far as I can tell — the limit is V8's RegExp stack, which any Node 22 build shares.
Only the webpack dev server is affected. next build (Turbopack) and next dev --turbopack are both fine, on 15.5.18 and on 16.3.1-canary.16.
The reproduction repo pins next@15.5.18 so the failure shows with a plain npm run dev. To check canary, install next@canary and run with --webpack (Turbopack is the dev default from 16 on).
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 the reproduction repository and compare the webpack dev behavior at the two documented input sizes. Then inspect next/dist/compiled/webpack/bundle5.js and compare its enhanced-resolve parseIdentifier implementation with the described standalone version. Done means the webpack dev request no longer hangs for the large module and compilation failures surface as an error instead of an unresolved request.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nextjs, node.js, webpack
- Domain
- build-system, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100