cloudflare / cloudflare/workerd

Response.clone() + HTMLRewriter.transform() deadlocks when clone is read first

Open
#6,436 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
8.7k
Forks
739
Avg merge
2d 20h
Merged PRs (30d)
174

Description

`Response.clone()` followed by `HTMLRewriter.transform(response)` deadlocks when the clone's body is consumed before the HTMLRewriter output. workerd kills the request with "your Worker's code had hung and would never generate a response".

Without HTMLRewriter, reading the clone first works fine — the tee branches are independent. HTMLRewriter appears to couple them, so the clone's branch can't be read unless the HTMLRewriter branch is also being consumed.

```js
export default {
async fetch() {
const response = new Response("

Hello

");
const clone = response.clone();
new HTMLRewriter()
.on("h1", { element(el) { el.setInnerContent("Rewritten"); } })
.transform(response);

// Hangs — tee branch for `clone` is blocked because HTMLRewriter
// holds the other branch and nothing is reading its output.
return new Response(await clone.text());
},
};
```

I think this is the root cause of [cloudflare/workers-sdk#7313](https://github.com/cloudflare/workers-sdk/issues/7313). The common pattern of `ctx.waitUntil(cache.put(req, response.clone()))` combined with `return new HTMLRewriter().transform(response)` deadlocks in `@cloudflare/vitest-pool-workers` tests, because `waitOnExecutionContext()` waits for `cache.put` (which needs to read the clone) before the test consumes the HTMLRewriter output.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.