{"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/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/fetch/23_request.js#L656-L692","documentation":"Request.prototype.clone() must tee the body stream so both copies can be read independently. If this request's body is already disturbed (read via text()/json()/stream reader) or locked (piped/stream-locked), teeing is impossible and clone() throws TypeError \"Body is unusable\". Bodies are single-use; clone only works on a request whose body has never been touched.","triggerScenarios":"const r = new Request(url, { method: \"POST\", body: \"x\" }); await r.text(); r.clone(); also r.clone() while the body is being piped to another stream.","commonSituations":"Clone-after-log patterns (read body for logging, then clone to forward); retry wrappers cloning a request after a failed attempt that already consumed the body; duplicate-processing pipelines.","solutions":["Clone first, then read: const dup = r.clone() before any body access, and read from the duplicate","Buffer the body up front (const body = await r.text()) and build two new Requests from the string","For file uploads you cannot buffer, pass the underlying Blob/File as body — it is re-readable and clone-safe"],"exampleFix":"// before\nconst r = new Request(url, { method: \"POST\", body: \"x\" });\nawait r.text();\nr.clone(); // throws: Body is unusable\n\n// after\nconst r = new Request(url, { method: \"POST\", body: \"x\" });\nconst dup = r.clone(); // clone before any read\nawait r.text();\n// dup is still fully readable","handlingStrategy":"validation","validationCode":"if (req.bodyUsed) {\n  throw new Error(\"Cannot clone: body already consumed — clone before reading\");\n}\nconst dup = req.clone();","typeGuard":"function isCloneableRequest(req: Request): boolean {\n  return !req.bodyUsed;\n}","tryCatchPattern":"try {\n  return req.clone();\n} catch (err) {\n  if (err instanceof TypeError && err.message === \"Body is unusable\") {\n    // reconstruct from buffered payload instead of cloning\n    return new Request(req.url, { method: req.method, headers: [...req.headers], body: buffered });\n  }\n  throw err;\n}","preventionTips":["Clone first, read second — make it a habit in log-and-forward middleware","Use re-readable body sources (Blob/File/Uint8Array) when duplicates are needed","Await any body read only after you have made all clones you need"],"tags":["fetch","request","clone","body","stream"],"backgroundTag":"body-already-consumed","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}