Skip to content

fix(ci): stop one aborted upload from killing wrangler dev - #20

Merged
yashau merged 1 commit into
mainfrom
claude/flaky-e2e-ci-wrangler-730456
Aug 19, 2026
Merged

fix(ci): stop one aborted upload from killing wrangler dev#20
yashau merged 1 commit into
mainfrom
claude/flaky-e2e-ci-wrangler-730456

Conversation

@yashau

@yashau yashau commented Aug 19, 2026

Copy link
Copy Markdown
Owner

The e2e job died mid-run and passed on a re-run. It was not flaky infrastructure and it was not the OOM killer.

What actually happened

wrangler dev exits on a single failed proxied request, and reports it as ✘ [ERROR] with an empty message.

Every request goes through wrangler's own ProxyWorker. When that inner fetch rejects:

  1. the ProxyWorker reports it to the ProxyController;
  2. DevEnv.handleErrorEvent finds no matching non-fatal case and re-emits it as a top-level error;
  3. the dev command is await events.once(devEnv, "teardown") — and Node's events.once rejects on error, so the command throws and the process exits 1;
  4. the cause crossed a Worker boundary, so it is a plain object rather than an Error; castErrorCause wraps it in new Error(), whose message is "".

Hence a fatal exit that names nothing. From the failing run:

[wrangler:info] GET /users/0199e2e0-0000-7000-8000-000000000023 200 OK (94ms)
✘ [ERROR]

# wrangler dev EXITED — code=1 signal=null

code=1 signal=null, no OOM kill recorded, 8 GB free.

The rejection is Network connection lost., raised when a client disconnects while its request body is still uploading. Playwright does that every time it closes a page with a form POST in flight — which is why it landed roughly twenty tests in, and why re-running "fixed" it.

Confirmed by reduction

Five aborted uploads against a bare Worker (no assets, no app code) reproduce the exact CI signature on wrangler 4.121.0, and survive it patched:

stock patched
aborted upload ✘ [ERROR] (empty), exit 1, port unbound Error proxying request to the local Worker: Network connection lost., still serving

Aborting mid-response is survivable; only mid-request-body is fatal.

The fix

patches/wrangler@4.121.0.patch applies upstream's own fix — cloudflare/workers-sdk#15207 for #15203: report the failed request and keep serving. Two call sites, because wrangler bundles the ProxyController twice (its own, and the remote-bindings copy).

Both upstream PRs for this are still open and main is still unfixed, so there is no release to upgrade to. Remove the patch when one carries the fix — a version bump that leaves it here fails the install rather than applying quietly, which is the intended prompt to go and check.

patches/** joins the js paths filter: a patched dependency is application behaviour, and editing it must run the suite that proves it still works.

Testing

  • Full suite locally: 100 passed, 1 flaky (an unrelated rbac-ui visibility assertion that passed on retry), wrangler dev alive throughout.
  • Targeted repro above, stock vs patched.
  • pnpm install --frozen-lockfile reapplies the patch from a clean store; verified 2 patched call sites, 0 fatal ones.
  • pnpm fmt:check clean; pre-commit hooks (typos, zizmor, actionlint, lint-js-repo, fmt-js) all pass.

🤖 Generated with Claude Code

The e2e job died mid-run and passed on a re-run. It was not flaky
infrastructure and it was not the OOM killer: `wrangler dev` exits on a
SINGLE failed proxied request, and reports it as `✘ [ERROR]` with an
empty message.

Wrangler forwards every request through its own ProxyWorker. When that
inner fetch rejects, the ProxyWorker reports it to the ProxyController,
`DevEnv.handleErrorEvent` finds no matching non-fatal case and re-emits
it as a top-level `error`; the dev command is
`await events.once(devEnv, "teardown")`, and Node's `events.once`
rejects on `error`, so the command throws and the process exits 1. The
cause crossed a Worker boundary, so it is a plain object rather than an
Error, and `castErrorCause` wraps it in `new Error()` -- message "".
Hence a fatal exit that names nothing.

The rejection is `Network connection lost.`, raised when a client
disconnects while its request body is still uploading. Playwright does
that every time it closes a page with a form POST in flight. Confirmed
by reduction: five aborted uploads against a bare Worker kill wrangler
4.121.0 with the exact CI signature, and survive it patched.

So the failure was one browser-side race taking down the server for the
rest of the suite -- seventy `ERR_CONNECTION_REFUSED` failures, three
attempts each, none of them naming the event.

Patch wrangler with upstream's own fix (cloudflare/workers-sdk#15207,
issue #15203): report the failed request and keep serving. Two call
sites, because wrangler bundles the ProxyController twice. Remove the
patch when a release carries the fix -- a version bump that leaves it
here fails the install rather than applying quietly.

`patches/**` joins the js paths filter: a patched dependency is
application behaviour, and editing it must run the suite that proves it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yashau
yashau force-pushed the claude/flaky-e2e-ci-wrangler-730456 branch from 3c0c5f8 to f686ea9 Compare August 19, 2026 21:44
@yashau yashau changed the title fix(e2e): stop one aborted upload from killing wrangler dev fix(ci): stop one aborted upload from killing wrangler dev Aug 19, 2026
@yashau
yashau merged commit df6b939 into main Aug 19, 2026
18 of 19 checks passed
@yashau
yashau deleted the claude/flaky-e2e-ci-wrangler-730456 branch August 19, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant