{"record":{"id":"abe3287dd6ef37fc","repo":"denoland/deno","slug":"body-already-consumed","errorCode":null,"errorMessage":"Body already consumed","messagePattern":"Body already consumed","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/fetch/22_body.js","lineNumber":189,"sourceCode":"   */\n  consumed() {\n    if (\n      ObjectPrototypeIsPrototypeOf(\n        ReadableStreamPrototype,\n        this.streamOrStatic,\n      )\n    ) {\n      return isReadableStreamDisturbed(this.streamOrStatic);\n    }\n    return this.streamOrStatic.consumed;\n  }\n\n  /**\n   * https://fetch.spec.whatwg.org/#concept-body-consume-body\n   * @returns {Promise<Uint8Array>}\n   */\n  consume() {\n    if (this.unusable()) throw new TypeError(\"Body already consumed\");\n    if (\n      ObjectPrototypeIsPrototypeOf(\n        ReadableStreamPrototype,\n        this.streamOrStatic,\n      )\n    ) {\n      readableStreamThrowIfErrored(this.stream);\n      return PromisePrototypeCatch(\n        readableStreamCollectIntoUint8Array(this.stream),\n        (e) => {\n          if (ObjectPrototypeIsPrototypeOf(BadResourcePrototype, e)) {\n            // TODO(kt3k): We probably like to pass e as `cause` if BadResource supports it.\n            throw new e.constructor(\n              \"Cannot read body as underlying resource unavailable\",\n            );\n          }\n          throw e;\n        },","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/fetch/22_body.js#L171-L207","documentation":"Thrown by InnerBody.consume() in ext/fetch/22_body.js when the body is unusable — the stream is locked or disturbed, or the static body was already consumed. This backs every one-shot body reader: request.json(), request.text(), request.arrayBuffer(), response.formData(), etc. A body can only be consumed once.","triggerScenarios":"Calling two one-shot readers on the same body: `(await req.text())` followed by `req.json()`; reading `res.body` with a reader and then calling `res.text()`; cloning after consumption; middleware that logs the body and then the handler reads it again.","commonSituations":"Logging middleware that calls request.json() before the route handler; error handlers that try to re-read the body after a failed parse; double-calling formData() in upload handlers; using the same Request object for fetch() after reading its body.","solutions":["Read the body once, then reuse the parsed value: `const data = await req.json().catch(() => null)` and pass `data` downstream.","When multiple consumers are needed, clone first: `const [a, b] = [req.clone(), req]` (clone before any read).","In middleware, buffer the body (await once) and reconstruct a new Request with the buffered bytes for downstream handlers."],"exampleFix":"// before\nconsole.log(await req.text());\nconst json = await req.json(); // Body already consumed\n\n// after\nconst raw = await req.text();\nconst json = JSON.parse(raw);","handlingStrategy":"validation","validationCode":"function bodyReadable(b) {\n  const s = b.body;\n  return s !== null && !(s.locked);\n}\nif (!bodyReadable(req)) throw new Error(\"body already used; buffer and pass the parsed value instead\");","typeGuard":"function hasUnreadBody(r: Request | Response): boolean {\n  return r.body === null || !(r.body.locked); // disturbed streams are not directly detectable; track reads yourself\n}","tryCatchPattern":"let data; try { data = await req.json(); } catch (e) { if (e instanceof TypeError && e.message === \"Body already consumed\") { /* re-fetch or use cached value */ } else throw e; }","preventionTips":["Read each body exactly once; pass the parsed value downstream.","Use req.clone() before the first read when two consumers need the body.","In middleware, buffer the body and rebuild the Request for the handler."],"tags":["fetch","body","stream","request-handling"],"backgroundTag":"request-body-already-read","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"}