# “TypeError: Body is unusable”: body has already been read

A request or response body can be read once. Reading it twice throws Body is unusable in Node and Next.js routes; browsers word it three other ways. Reproduced.

Author: Formgong team
Published: 2026-10-16
Updated: 2026-10-23
Language: en
Canonical: https://formgong.com/en/blog/body-is-unusable-body-has-already-been-read/

Body is unusable means the code read a request or response body that was already read. A body is a stream and can be consumed only once, by json(), text() or formData(). Read it once, keep the result in a variable and pass that on. If two readers really need it, call clone() before the first read.

## What we saw

*Figure: A contact form shows an error after Send. The Next.js terminal shows TypeError Body is unusable: Body has already been read, and the browser receives an empty 500.*

On 16.10.2026 we wrote a Next.js 16.4.2 route that reads `await request.json()`, logs a field, and then reads `request.json()` again, the way a logging helper or a validation library might. The first read worked. The second threw `TypeError: Body is unusable: Body has already been read`, and the route answered 500 with an empty body. In the browser that empty 500 then broke `response.json()` with [“Unexpected end of JSON input”](/en/blog/unexpected-token-doctype-is-not-valid-json/), so the visitor's side shows a different error from the server's.

The same mistake on a response in the browser gave a different message in each engine:

Reading a body twice
WhereMessage

Node 22 and Next.js route handlers`TypeError: Body is unusable: Body has already been read`
Chromium 152`TypeError: Failed to execute 'json' on 'Response': body stream already read`
Firefox 142`TypeError: Response.json: Body has already been consumed.`
WebKit 26 (Safari)`TypeError: Body is disturbed or locked`
Cloudflare Workers (workerd)`TypeError: Body has already been used. It can only be used once. Use tee() first if you need to read it twice.`

We check the Workers row with a test in this site's own code: it reads a body twice in the Workers runtime and compares the error with the row.

## Why a body can be read only once

A request or response body is a stream. `json()`, `text()`, `formData()` and `arrayBuffer()` each read the stream to the end, and after that nothing is left to read. It often happens without a second `json()` in sight: middleware or an auth helper reads the body first, a `console.log(await response.text())` added for debugging sits above the real `json()`, or a retry reuses the same `Response`.

## Read once, or clone first

Keep the parsed body in a variable and pass it to whatever needs it. If two parts of the code really need the raw stream, call `clone()` before the first read and give each reader its own copy. The `tee()` in the Cloudflare message splits the body stream in two, and `clone()` calls it for you.

```javascript
export async function POST(request) {
  const body = await request.json(); // read once
  await logRequest(body);            // pass the parsed value on
  await saveMessage(body);
  return Response.json({ ok: true });
}

// If two places really need the raw body, clone before the first read:
// const copy = request.clone(); const forLog = await copy.text();
```

## If the route only forwards a contact form

A route that exists only to pass form fields on to email can be dropped: the form can post straight to [Formgong](/en/) at `https://formgong.com/submit`, and there is no body of yours to read twice. See the [HTML guide](/en/docs/html/).

## Frequently asked questions

### What does TypeError: Body is unusable mean?

The code tried to read a request or response body that had already been read. A body is a stream and can be read only once.

### How do I read a request body twice?

Call request.clone() before the first read and read the copy, or read the body once and pass the parsed value to the code that needs it.

### What is the browser version of this error?

Chrome: body stream already read. Firefox: Body has already been consumed. Safari: Body is disturbed or locked.

### What does Body has already been used. Use tee() first mean in Cloudflare Workers?

It is the Workers wording of the same error: the code read a request or response body that was already read. Read it once and pass the value on, or call clone() before the first read.

## Sources and documentation

- [MDN: Request.clone()](https://developer.mozilla.org/en-US/docs/Web/API/Request/clone)
- [MDN: Response.bodyUsed](https://developer.mozilla.org/en-US/docs/Web/API/Response/bodyUsed)
- [Next.js: Route handlers](https://nextjs.org/docs/app/api-reference/file-conventions/route)
- [HTML contact form](https://formgong.com/en/docs/html/)

[Get a form key](https://formgong.com/en/#top)
