What versions & operating system are you using?
System:
OS: Linux 6.8 Ubuntu 24.04.4 LTS 24.04.4 LTS (Noble Numbat)
CPU: (6) x64 AMD EPYC-Milan Processor
Memory: 13.01 GB / 15.61 GB
Container: Yes
Shell: 5.2.21 - /bin/bash
Binaries:
Node: 22.23.2 - /usr/bin/node
npm: 10.9.8 - /usr/bin/npm
pnpm: 9.0.0 - /usr/bin/pnpm
npmPackages:
wrangler: ^4.123.0 => 4.123.0
(workerd 1.20260811.1 and miniflare 5.20260811.1-alpha come in as wrangler's dependencies.)
Please provide a link to a minimal reproduction
https://gist.github.com/June157/7dd408450d8c153b47986a8c3325132c
(5 files: worker.mjs, wrangler.json, hammer.mjs, index.html → put under public/, and a README with the two commands.)
Describe the Bug
With Static Assets configured (assets.directory), wrangler dev exits — not just returns an error — after a few dozen POST requests that carry a body and target a path where an asset exists. The assets layer answers those requests with 405 itself (they never reach the user Worker), and after some number of them the ProxyWorker dies. The same POSTs without a body are fine indefinitely, and the same Worker without assets is fine indefinitely.
Client-side symptom: 405 … 405 → one or two HTTP 500 → socket hang up / ECONNRESET → ECONNREFUSED for everything after. wrangler dev prints an empty ✘ [ERROR] and exits.
Production Workers with the same code do not exhibit this.
Minimal reproduction (also in the gist)
worker.mjs — its content barely matters; the crashing requests never reach it:
export default {
fetch(request) {
if (request.method === "POST") return new Response("Forbidden", { status: 403 });
return new Response("ok");
},
};
wrangler.json:
{ "name": "repro", "main": "worker.mjs", "compatibility_date": "2026-08-13",
"assets": { "directory": "./public", "binding": "ASSETS" } }
public/index.html: any file (so that / is an asset path).
npx wrangler dev -c wrangler.json --port 8788
# in another shell — 300 POSTs with a small form body, 3 concurrent:
node --input-type=module -e '
const N=300,C=3,B="http://127.0.0.1:8788";let i=0,ok=0,fail=0;
const one=()=>fetch(B+"/",{method:"POST",body:"a=b",headers:{"content-type":"application/x-www-form-urlencoded"}});
await Promise.all(Array.from({length:C},async()=>{while(i<N){i++;try{const r=await one();if(r.status>=500)throw 0;ok++}catch{fail++}}}));
console.log({ok,fail});'
Observed: e.g. { ok: 107, fail: 193 }; afterwards curl http://127.0.0.1:8788/ → connection refused. Successful responses are 405 (from the assets layer, not from the Worker).
Expected: 300 × 405 (or the request forwarded to the Worker), and wrangler dev stays up.
What I varied (300 requests each, 2–3 runs each)
| Variation |
Result |
Same config, POST / without body |
✅ 300 × 405, alive |
Same config, POST /api/x (no asset there) with body → reaches Worker → 403 |
✅ 300 × 403, alive |
Same config, POST / with body, concurrency 1 |
❌ dies (first failure at request 9) |
No assets in config, POST / with body → 403 from Worker |
✅ alive |
+ compatibility_flags: ["nodejs_compat"] |
no change either way |
+ assets.html_handling: "drop-trailing-slash" |
no change |
+ public/_headers or public/_redirects |
no change |
Worker drains the body (await request.text()) before responding |
irrelevant — request doesn't reach the Worker |
So the necessary conditions I could isolate are: assets configured + POST with a body + path resolves to an asset (assets layer answers 405).
Where I hit it (possibly related, not reduced)
In an Astro site on @astrojs/cloudflare, the same crash signature also occurs on POST /api/contact (an SSR route, not an asset) when the request has a form body and no Origin header — Astro's CSRF middleware answers 403 without reading the body. The identical request with an Origin header (handler reads the body, answers 400) never crashes, and the same request without a body never crashes. I could not reduce that variant to a bare Worker: a bare Worker returning 403 to the same request on a non-asset path stays up. I mention it because it may be the same underlying stream-handling issue reached by a different route; happy to provide the Astro repro if useful.
Guess at the mechanism (unverified)
With assets, requests pass through an asset router before the user Worker. When the router itself answers (405 for POST-to-asset) while a request body is still in flight, the abandoned body stream seems to surface as Network connection lost inside the ProxyWorker and is treated as fatal for the whole dev server rather than for that one request.
Please provide any relevant error logs
Debug log (~/.config/.wrangler/logs/wrangler-*.log) at the moment of the crash:
Error in ProxyController: Error inside ProxyWorker
Error
at castErrorCause (…/wrangler/wrangler-dist/cli.js:179580:20)
at ProxyController2.emitErrorEvent (…/wrangler/wrangler-dist/cli.js:280188:20)
at ProxyController2.onProxyWorkerMessage (…/wrangler/wrangler-dist/cli.js:280065:18)
at PROXY_CONTROLLER (…/wrangler/wrangler-dist/cli.js:279792:24)
at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
at async #handleLoopbackCustomFetchService (…/miniflare/dist/src/index.js:111517:22)
at async #handleLoopback (…/miniflare/dist/src/index.js:111748:20) {
cause: {
name: 'Error',
message: 'Network connection lost.',
stack: 'Error: Network connection lost.'
}
}
The user Worker's runtime WebSocket had opened ~2 s earlier; there is nothing between Runtime.enable and this error in the debug log.
What versions & operating system are you using?
(workerd 1.20260811.1 and miniflare 5.20260811.1-alpha come in as wrangler's dependencies.)
Please provide a link to a minimal reproduction
https://gist.github.com/June157/7dd408450d8c153b47986a8c3325132c
(5 files:
worker.mjs,wrangler.json,hammer.mjs,index.html→ put underpublic/, and a README with the two commands.)Describe the Bug
With Static Assets configured (
assets.directory),wrangler devexits — not just returns an error — after a few dozen POST requests that carry a body and target a path where an asset exists. The assets layer answers those requests with405itself (they never reach the user Worker), and after some number of them the ProxyWorker dies. The same POSTs without a body are fine indefinitely, and the same Worker withoutassetsis fine indefinitely.Client-side symptom:
405…405→ one or twoHTTP 500→socket hang up/ECONNRESET→ECONNREFUSEDfor everything after.wrangler devprints an empty✘ [ERROR]and exits.Production Workers with the same code do not exhibit this.
Minimal reproduction (also in the gist)
worker.mjs— its content barely matters; the crashing requests never reach it:wrangler.json:{ "name": "repro", "main": "worker.mjs", "compatibility_date": "2026-08-13", "assets": { "directory": "./public", "binding": "ASSETS" } }public/index.html: any file (so that/is an asset path).Observed: e.g.
{ ok: 107, fail: 193 }; afterwardscurl http://127.0.0.1:8788/→ connection refused. Successful responses are405(from the assets layer, not from the Worker).Expected: 300 × 405 (or the request forwarded to the Worker), and
wrangler devstays up.What I varied (300 requests each, 2–3 runs each)
/without body/api/x(no asset there) with body → reaches Worker → 403/with body, concurrency 1assetsin config, POST/with body → 403 from Workercompatibility_flags: ["nodejs_compat"]assets.html_handling: "drop-trailing-slash"public/_headersorpublic/_redirectsawait request.text()) before respondingSo the necessary conditions I could isolate are:
assetsconfigured + POST with a body + path resolves to an asset (assets layer answers 405).Where I hit it (possibly related, not reduced)
In an Astro site on
@astrojs/cloudflare, the same crash signature also occurs onPOST /api/contact(an SSR route, not an asset) when the request has a form body and noOriginheader — Astro's CSRF middleware answers 403 without reading the body. The identical request with anOriginheader (handler reads the body, answers 400) never crashes, and the same request without a body never crashes. I could not reduce that variant to a bare Worker: a bare Worker returning 403 to the same request on a non-asset path stays up. I mention it because it may be the same underlying stream-handling issue reached by a different route; happy to provide the Astro repro if useful.Guess at the mechanism (unverified)
With
assets, requests pass through an asset router before the user Worker. When the router itself answers (405 for POST-to-asset) while a request body is still in flight, the abandoned body stream seems to surface asNetwork connection lostinside the ProxyWorker and is treated as fatal for the whole dev server rather than for that one request.Please provide any relevant error logs
Debug log (
~/.config/.wrangler/logs/wrangler-*.log) at the moment of the crash:The user Worker's runtime WebSocket had opened ~2 s earlier; there is nothing between
Runtime.enableand this error in the debug log.