{"record":{"id":"934eec92258a64db","repo":"denoland/deno","slug":"body-is-unusable-934eec","errorCode":null,"errorMessage":"Body is unusable","messagePattern":"Body is unusable","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/23_response.js","lineNumber":841,"sourceCode":"    return this[_response].statusMessage;\n  }\n\n  /**\n   * @returns {Headers}\n   */\n  get headers() {\n    webidl.assertBranded(this, ResponsePrototype);\n    return responseHeaders(this);\n  }\n\n  /**\n   * @returns {Response}\n   */\n  clone() {\n    webidl.assertBranded(this, ResponsePrototype);\n    materializeLazyStaticBody(this);\n    if (this[_body] && this[_body].unusable()) {\n      throw new TypeError(\"Body is unusable\");\n    }\n    const second = webidl.createBranded(Response);\n    const newRes = cloneInnerResponse(this[_response]);\n    initializeResponseBase(second, newRes, responseHeaderGuard(this));\n    return second;\n  }\n\n  [SymbolFor(\"Deno.privateCustomInspect\")](inspect, inspectOptions) {\n    return inspect(\n      createFilteredInspectProxy({\n        object: this,\n        evaluate: ObjectPrototypeIsPrototypeOf(ResponsePrototype, this),\n        keys: [\n          \"body\",\n          \"bodyUsed\",\n          \"headers\",\n          \"ok\",\n          \"redirected\",","sourceCodeStart":823,"sourceCodeEnd":859,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/fetch/23_response.js#L823-L859","documentation":"Thrown by Response.clone() when the response's body stream has already been disturbed (read, piped, cancelled, or locked by a reader) or has errored. The fetch spec requires clone() to tee an untouched stream so both copies stay readable, so a used body cannot be cloned. Deno first materializes lazy static bodies (responses created from strings/ArrayBuffers), so this only fires for genuinely consumed or errored streams.","triggerScenarios":"Calling res.text(), res.json(), res.arrayBuffer(), res.formData(), res.body.getReader().read(), or res.body.cancel() on a Response and then calling res.clone() on the same Response; or cloning a streaming response whose body errored mid-transfer.","commonSituations":"Logging or caching middleware that parses the body first and tries to clone afterwards; retry wrappers that clone after inspection; interceptor chains where an earlier layer already consumed the body; tests that await the body twice.","solutions":["Clone immediately after fetch() resolves, before any read: const copy = res.clone()","Check res.bodyUsed === false before calling clone()","If the body is already consumed, re-issue the fetch instead of cloning","For manual splitting of a partially read stream, use res.body.tee() on a still-locked-free stream instead of clone()"],"exampleFix":"// before\nconst data = await res.json();\nconst copy = res.clone(); // TypeError: Body is unusable\n\n// after\nconst copy = res.clone(); // clone before any read\nconst data = await res.json();","handlingStrategy":"validation","validationCode":"function isCloneable(res) {\n  return !res.bodyUsed && (!res.body || !res.body.locked);\n}\n// usage\nif (isCloneable(res)) {\n  const copy = res.clone();\n} else {\n  // body already consumed: refetch or reuse parsed data\n}","typeGuard":"function isCloneable(res: Response): boolean {\n  return !res.bodyUsed && (res.body === null || !res.body.locked);\n}","tryCatchPattern":"try {\n  const copy = res.clone();\n} catch (err) {\n  if (err instanceof TypeError && err.message === \"Body is unusable\") {\n    // body already consumed; refetch or reuse the parsed value\n  } else throw err;\n}","preventionTips":["Clone immediately after fetch resolves, before passing the Response anywhere","Check res.bodyUsed before clone() in wrappers and middleware","Parse once and pass the parsed value to consumers instead of sharing a Response","Remember res.body.getReader() locks the body even before the first read"],"tags":["fetch","response","stream","body","clone"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}