Cloudflare Workers: "code had hung" Error 1101 fix
Error: The Workers runtime canceled this request because it detected that your Worker's code had hung and would never generate a response. is not a timeout and it is not a slow origin. The runtime emits it the moment it can prove that the request's handler will never return a Response — and the most common way to build that situation is a promise that one request created and a different request awaited.
I reproduced both shapes of that mistake in workerd 2026-09-15, the engine behind wrangler dev, on an arm64 host with Node 26.5.1. A module-scope barrier promise that another request resolves is refused in 1.2 ms with an HTTP 500 and two distinct log lines — one of them names the file and line of the resolve call. A cached in-flight fetch() awaited by the next request just hangs: 45 s with no response and, at default log verbosity, no diagnostic at all. In production the first of those reaches the user as Error 1101; the second never answers.
Every number and every quoted log line below comes from those runs on 2026-09-15. If you are here because production is down, jump to the grep list — it is four patterns, and one of them is almost certainly your bug.
TL;DR
- The cancellation is proof-based, not timer-based. Cloudflare's wording is that it happens when "all the code associated with the request has executed and no events are left in the event loop, but a Response has not been returned". Measured: 1.2–1.6 ms across four runs (1.204, 1.215, 1.258, 1.647 ms). Nothing here is waiting 30 s for an origin.
- A promise resolved by another request gives you a log line that names the culprit.
Warning: A promise was resolved or rejected from a different request context ...followed byat Object.fetch (worker.js:26:7)— line 26 was theresolveReady("go")call, inside the request that resolved it. - A cached in-flight
fetch()is the silent version of the same bug. The awaiting request never gets an answer (measured ≥45 s) and workerd says nothing about it at default verbosity. That is the one that looks like a hung origin in your dashboard. - Promises belong to the request that created them. Plain data does not. Cache the resolved value, report state instead of awaiting another invocation's promise, and reach for Durable Objects or Workers KV when you need real cross-request coordination.
- The compatibility flag the warning suggests removes the warning, not the failure. With
no_handle_cross_request_promise_resolutionset, the awaiting request still returned 500 in 1.2 ms, and the resolving side then threwCannot perform I/O on behalf of a different request. - You can reproduce all of it with no Cloudflare account. workerd ships these exact strings; the lab below is one Cap'n Proto config and one file you swap between broken and fixed.