Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

Response Body Already Used: Read Once or Clone Before Consumption

A response body is a consumable stream.

By ON Lab2 min readSources checked November 10, 2026 (KST)

A response body is a consumable stream. Reuse the parsed value for ordinary logging and processing; create a clone before consumption only when a separate stream reader is actually required.

Reproduce the behavior safely

Run this self-contained fixture in an empty temporary directory, separate from your project. Shell examples create only named fixture files there. JavaScript examples use local values and send no network requests.

const assert = require('node:assert/strict');
(async () => {
  const response = new Response('{"count":4}');
  const duplicate = response.clone();
  const data = await response.json();
  assert.equal(response.bodyUsed, true);
  await assert.rejects(() => response.text(), TypeError);
  assert.equal(await duplicate.text(), '{"count":4}');
  assert.equal(data.count, 4);
  assert.throws(() => response.clone(), TypeError);
  console.log('parsed once; early clone readable; late clone rejected');
})().catch(e => { console.error(e); process.exitCode = 1; });

Observed local output

parsed once; early clone readable; late clone rejected

Why the result changes

Calling json does more than convert text: it consumes the original body. Logging response.text and later returning response.json therefore asks two readers to consume one stream. Logging the already parsed data avoids that second read. A clone prepared before reading provides another branch, while a clone requested after use cannot repair the original stream.

Choose and verify the correction

Find every consumer in the request path, including debug logging, cache helpers and error handlers. Give one component ownership of parsing and pass its value onward. For a deliberate cache-and-return workflow, prepare the clone before handing either response to its consumer and await or otherwise own both tasks. In tests, create a new Response for each mocked request rather than returning the same consumed instance repeatedly.

Limits and next checks

The local fixture uses Node Response without network or service-worker execution. Cloning is not a free logging technique for large downloads: unread data on a slower branch can accumulate without a fixed limit. Prefer streaming with explicit ownership for large bodies. A body can also be locked by a reader, so bodyUsed alone is not a complete permission check. HTTP status policy remains a separate check.

Related: Fetch Resolves a 404 Response: Check HTTP Status Before Parsing Success Data.

Isolated fixture executed on macOS on November 10, 2026 (KST), with v26.5.0. The observed output verifies this example, not every application or runtime.

Sources & further reading