Summary
A bare GET / to a next-intl app (no locale prefix) returns no response under perry (curl exit 28 / 000) where Node returns 307. It's deterministic, and each hit leaks a request/connection so that ~8 of them wedge the whole server.
Deterministic trigger (isolated)
Same standalone server (gscmaster, Next 16.1.1 + next-intl), single-threaded, warm:
| request |
perry |
node |
/en (explicit locale) |
307 ✓ |
307 |
/ + Cookie: NEXT_LOCALE=de |
307 ✓ |
307 |
/ + Accept-Language: de |
307 → /de ✓ |
307 → /de |
/ bare (no cookie, no Accept-Language) |
000 |
307 (→ /, Set-Cookie: NEXT_LOCALE=en) |
/ + Accept-Language: en (default locale) |
000 |
307 |
The failing case is exactly the locale-detection / default path: no cookie and no Accept-Language. The winning cases (/en, /+cookie, /+AL) produce a byte-identical 307+Set-Cookie response — so it is not the response shape, redirect-to-self, absolute Location, or cookie (a minimal res.writeHead(307,{Location,Set-Cookie}); res.end(body) server handles all of those correctly under perry).
Localization
.next/server/chunks/[root-of-the-server]__…._.js middleware does:
new Negotiator({ headers: { "accept-language": e.get("accept-language") || void 0 } }).languages()
When Accept-Language is absent this passes undefined to Negotiator (the default-locale branch). On that path the async middleware() promise never settles under perry: no response is written (res.end() never called → the response oneshot is dropped → 000), and no error is logged. Each drop leaks the pending request; ~8 kill the server. A single hit fails but the server survives.
Headers.get("accept-language") for a missing header correctly returns null, and null || undefined === undefined (verified). So the drop is downstream — a lost async continuation in the default-locale middleware path (same class as #5989 "dynamic RSC render evaporates" and the streaming-race #6477), not the header read.
Impact
Any next-intl (or middleware-locale-detecting) app: the bare / root — the entry point — hangs for a client that sends no Accept-Language, and repeated hits take the server down.
Summary
A bare
GET /to anext-intlapp (no locale prefix) returns no response under perry (curlexit 28 /000) where Node returns307. It's deterministic, and each hit leaks a request/connection so that ~8 of them wedge the whole server.Deterministic trigger (isolated)
Same standalone server (gscmaster, Next 16.1.1 + next-intl), single-threaded, warm:
/en(explicit locale)307✓307/+Cookie: NEXT_LOCALE=de307✓307/+Accept-Language: de307→/de✓307→/de/bare (no cookie, no Accept-Language)000307(→/,Set-Cookie: NEXT_LOCALE=en)/+Accept-Language: en(default locale)000307The failing case is exactly the locale-detection / default path: no cookie and no
Accept-Language. The winning cases (/en,/+cookie,/+AL) produce a byte-identical307+Set-Cookieresponse — so it is not the response shape, redirect-to-self, absolute Location, or cookie (a minimalres.writeHead(307,{Location,Set-Cookie}); res.end(body)server handles all of those correctly under perry).Localization
.next/server/chunks/[root-of-the-server]__…._.jsmiddleware does:When
Accept-Languageis absent this passesundefinedto Negotiator (the default-locale branch). On that path the asyncmiddleware()promise never settles under perry: no response is written (res.end()never called → the response oneshot is dropped →000), and no error is logged. Each drop leaks the pending request; ~8 kill the server. A single hit fails but the server survives.Headers.get("accept-language")for a missing header correctly returnsnull, andnull || undefined === undefined(verified). So the drop is downstream — a lost async continuation in the default-locale middleware path (same class as #5989 "dynamic RSC render evaporates" and the streaming-race #6477), not the header read.Impact
Any next-intl (or middleware-locale-detecting) app: the bare
/root — the entry point — hangs for a client that sends noAccept-Language, and repeated hits take the server down.