Link to the code that reproduces this issue
https://github.com/Onebu/turbopack-forof-return-repro
To Reproduce
pnpm install && pnpm dev (next 15.4.11, next dev --turbopack)
curl http://localhost:3000/api/repro
The route imports a named function and references it after a for...of loop whose body ends in an unconditional return:
import { beta } from '../../../lib/util'
export function GET(request: Request): Response {
const url = new URL(request.url)
const items: string[] = url.searchParams.get('items')?.split(',') ?? []
for (const item of items) {
if (item === 'ok') continue
return Response.json({ bad: item })
}
return Response.json({ typeofBinding: typeof beta })
}
Current vs. Expected behavior
Current (15.4.11): response is {"typeofBinding":"undefined"}. In the compiled dev chunk (.next/server/chunks/*), references to the imported binding placed after the loop are left as the bare identifier instead of being rewritten to __TURBOPACK__imported__module__...["beta"] — so calling it throws ReferenceError: beta is not defined at runtime. References before the loop in the same function, and all references in sibling functions, are rewritten correctly.
Expected: {"typeofBinding":"function"} — which is what next 16.2.10 returns for the identical app, and what webpack dev/build produce on 15.4.11.
Notes from a larger app where we hit this in production code:
- Deterministic, survives recompiles/HMR; not a race.
- Positional, not name-based: aliasing the import (
import { beta as b }) just moves the ReferenceError to the new name; importing directly from the source module instead of a barrel doesn't help either.
- The trigger is precisely the loop body being unable to complete normally via an unconditional tail
return: making that return conditional (if (item !== '') return ...) fixes resolution; deleting it fixes it as well. Template literals, ?./??, and outer-scope writes near the loop were all ruled out.
- Real-world impact in our app: a route handler's server-side validation call after such a loop threw
ReferenceError, was swallowed by a fail-open catch, and validation was silently skipped in dev only.
Since 16.x is fixed, this is presumably already known internally or fixed incidentally — filing mainly in case a 15.x backport is considered, and for searchability (the symptom is very hard to attribute: the ReferenceError carries the original identifier name and looks like a scoping bug in user code).
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin 25.5.0
Available memory (MB): 32768
Available CPU cores: 10
Binaries:
Node: 22.22.2
npm: 10.9.7
pnpm: 10.33.0
Relevant Packages:
next: 15.4.11
react: 19.2.7
react-dom: 19.2.7
typescript: 6.0.3
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
Turbopack
Which stage(s) are affected? (Select all that apply)
next dev (local)
Link to the code that reproduces this issue
https://github.com/Onebu/turbopack-forof-return-repro
To Reproduce
pnpm install && pnpm dev(next 15.4.11,next dev --turbopack)curl http://localhost:3000/api/reproThe route imports a named function and references it after a
for...ofloop whose body ends in an unconditionalreturn:Current vs. Expected behavior
Current (15.4.11): response is
{"typeofBinding":"undefined"}. In the compiled dev chunk (.next/server/chunks/*), references to the imported binding placed after the loop are left as the bare identifier instead of being rewritten to__TURBOPACK__imported__module__...["beta"]— so calling it throwsReferenceError: beta is not definedat runtime. References before the loop in the same function, and all references in sibling functions, are rewritten correctly.Expected:
{"typeofBinding":"function"}— which is what next 16.2.10 returns for the identical app, and what webpack dev/build produce on 15.4.11.Notes from a larger app where we hit this in production code:
import { beta as b }) just moves the ReferenceError to the new name; importing directly from the source module instead of a barrel doesn't help either.return: making that return conditional (if (item !== '') return ...) fixes resolution; deleting it fixes it as well. Template literals,?./??, and outer-scope writes near the loop were all ruled out.ReferenceError, was swallowed by a fail-opencatch, and validation was silently skipped in dev only.Since 16.x is fixed, this is presumably already known internally or fixed incidentally — filing mainly in case a 15.x backport is considered, and for searchability (the symptom is very hard to attribute: the ReferenceError carries the original identifier name and looks like a scoping bug in user code).
Provide environment information
Which area(s) are affected? (Select all that apply)
Turbopack
Which stage(s) are affected? (Select all that apply)
next dev (local)