cloudflare / cloudflare/workers-sdk

miniflare 5.20260911.0-alpha: Response.clone() on a dispatchFetch response (DO-forwarded stream) throws "Body has already been consumed" although bodyUsed is false

Open
#15,635 1 comment 0 reactions 0 assignees View on GitHub
package:miniflare regression
Dominant language
TypeScript
Stars
4.5k
Forks
1.5k
Avg merge
3d 8h
Merged PRs (30d)
187

Description

### What versions & operating system are you using?

- miniflare `5.20260911.0-alpha` (workerd `1.20260911.1`), wrangler `4.131.1` — **fails**
- miniflare `5.20260907.0-alpha` (workerd `1.20260907.1`), wrangler `4.129.1` — **passes** (control, same Worker and test)
- Node `24.18.0`, macOS 25.5 (arm64)

### Please provide a link to a minimal reproduction

No public repository yet; the reproduction shape is small and described below (happy to extract it into a standalone repo if useful).

### Describe the Bug

Since miniflare `5.20260911.0-alpha`, calling `response.clone()` on a `Response` returned by `mf.dispatchFetch()` throws `TypeError: Response.clone: Body has already been consumed`, even though immediately before the clone the response reports `bodyUsed === false`, `body !== null`, `status === 201`.

Setup: the Worker forwards `/api/...` requests to a Durable Object with `stub.fetch(new Request(request, { headers }))` and returns `new Response(result.body, result)` (re-wrapped to add headers); the DO answers with `Response.json({...}, { status: 201 })`.

Observed on the same run, same Worker, same forwarding path:

- 32 concurrent `POST` requests with a ~600 KB **JSON** body (`content-type: application/json`) → all `201`, `response.clone().text()` works.
- 32 concurrent `POST` requests with a 600 KB **binary** body (`content-type: audio/webm`, `content-length: 600000`, `body: new Uint8Array(600000)`) → all `201`, `response.bodyUsed === false`, `response.body !== null`, response `content-type: application/json` — and `await response.clone().text()` throws for each.

So the response side is identical (a DO `Response.json` forwarded as a stream); the difference is the request body type/size. On `5.20260907.0-alpha` both bursts pass.

Expected: `clone()` succeeds while `bodyUsed` is `false`, as on `5.20260907.0-alpha`.

### Please provide any relevant error logs

```
TypeError: Response.clone: Body has already been consumed.
at webidl.errors.exception (node_modules/undici/lib/web/webidl/index.js:35:10)
at _Response.clone (node_modules/undici/lib/web/fetch/response.js:235:27)
at _Response.clone (node_modules/miniflare/dist/src/index.js:64074:28)
at : `await response.clone().text()` after `mf.dispatchFetch(...)`
```

Probe output on the same responses just before the clone (bumped tree):

```
media statuses=201 bodyUsed=false hasBody=true ctype=application/json
```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the regression through miniflare's mf.dispatchFetch() with the Durable Object forwarding path, comparing the passing and failing alpha versions. Exercise the 32-request JSON and binary-body cases and inspect the returned Response before clone(); done means response.clone().text() succeeds when bodyUsed is false, matching 5.20260907.0-alpha.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.