{"record":{"id":"e5276ff0c31662c8","repo":"denoland/deno","slug":"body-is-unusable","errorCode":null,"errorMessage":"Body is unusable","messagePattern":"Body is unusable","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/23_request.js","lineNumber":674,"sourceCode":"    }\n    return referrer;\n  }\n\n  get referrerPolicy() {\n    webidl.assertBranded(this, RequestPrototype);\n    return this[_request].referrerPolicy ?? \"\";\n  }\n\n  get signal() {\n    webidl.assertBranded(this, RequestPrototype);\n    return this[_signal];\n  }\n\n  clone() {\n    const prefix = \"Failed to execute 'Request.clone'\";\n    webidl.assertBranded(this, RequestPrototype);\n    if (this[_body] && this[_body].unusable()) {\n      throw new TypeError(\"Body is unusable\");\n    }\n    const clonedReq = cloneInnerRequest(this[_request]);\n\n    const materializedSignal = this[_signal];\n    const clonedSignal = createDependentAbortSignal(\n      [materializedSignal],\n      prefix,\n    );\n\n    const request = new Request(_brand);\n    request[_request] = clonedReq;\n    request[_signalCache] = clonedSignal;\n    headerListFromHeaders(this[_headers]);\n    request[_headersGuard] = guardFromHeaders(this[_headers]);\n    return request;\n  }\n\n  [SymbolFor(\"Deno.privateCustomInspect\")](inspect, inspectOptions) {","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/fetch/23_request.js#L656-L692","documentation":"Request.prototype.clone() checks this[_body].unusable() first: if the body stream is already disturbed or locked, clone() throws TypeError 'Body is unusable'. Cloning must tee the underlying stream, which is only possible before anything has read it. The message has the prefix 'Failed to execute Request.clone' in the error cause chain of the outer DOMException.","triggerScenarios":"const r = new Request(url, { method: 'POST', body: 'x' }); await r.text(); r.clone() — any read, iteration, or pipe of the body before clone().","commonSituations":"Retry/middleware code that clones a request after logging its body; clone-then-read ordering bugs in async handlers where an earlier await consumed the stream.","solutions":["Clone before first read: const copy = req.clone(); then read one of them","If already read, reconstruct a new Request from the buffered body string/bytes instead of cloning","Read via req.blob()/text() once and pass the materialized value to all consumers"],"exampleFix":"// before\nconst data = await req.text();\nconst copy = req.clone(); // throws: body disturbed\n\n// after\nconst copy = req.clone(); // tee while unused\nconst data = await req.text();\n// copy still has an independent unread body","handlingStrategy":"validation","validationCode":"function cloneOrRebuild(req, bodyTextIfRead) {\n  try {\n    return req.clone();\n  } catch {\n    return new Request(req.url, {\n      method: req.method,\n      headers: req.headers,\n      body: bodyTextIfRead,\n    });\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  copy = req.clone();\n} catch (err) {\n  if (err instanceof TypeError && /Body is unusable|Failed to execute 'Request.clone'/.test(String(err.cause ?? err.message))) {\n    copy = new Request(req.url, { method: req.method, headers: req.headers, body: buffered });\n  } else throw err;\n}","preventionTips":["Clone before the first body read, always","Keep a buffered copy (text/bytes) when a request body must be reused","Order handler code so clone() precedes any await that may consume the body"],"tags":["fetch","request","clone","body","stream"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}