Skip to content

Bug: expected non-null body source when passing a Request object to fetch AND receiving an error response (Node >= 24.14.0) #90826

@masakij

Description

@masakij

Link to the code that reproduces this issue

https://github.com/masakij/nextjs-expected-non-null-body-source-repro

To Reproduce

The reproduction is very simple. Execute this inside an App Router handler (e.g., Server Action or Route Handler) targeting an endpoint that returns a 4xx or 5xx error:

// 1. Create a Request object with a body
const req = new Request('https://httpstat.us/401', { // An endpoint that returns 401
  method: 'POST',
  body: JSON.stringify({ test: true }),
  headers: { 'Content-Type': 'application/json' }
});

// 2. Pass the Request object directly to global fetch
// 💥 This crashes immediately on Node >= 24.14.0 when the response is an error
const res = await fetch(req);

Current vs. Expected behavior

Expected Behavior:

The patched fetch should return the Response object with res.ok === false without crashing, just as it does in a pure Node.js environment.

Actual Behavior:

The application crashes with TypeError: expected non-null body source at ignore-listed frames.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 25.3.0: Wed Jan 28 20:53:31 PST 2026; root:xnu-12377.81.4~5/RELEASE_ARM64_T8122
  Available memory (MB): 16384
  Available CPU cores: 8
Binaries:
  Node: 24.14.0
  npm: 11.9.0
  Yarn: N/A
  pnpm: 10.29.3
Relevant Packages:
  next: 16.1.6 // Latest available version is detected (16.1.6).
  eslint-config-next: N/A
  react: 19.2.4
  react-dom: 19.2.4
  typescript: 5.9.3
Next.js Config:
  output: standalone

Which area(s) are affected? (Select all that apply)

Not sure

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

Description:

In the App Router environment, using the global patched fetch crashes with TypeError: expected non-null body source under a very specific set of conditions:

You pass a Request object (that contains a body, e.g., POST/PUT) directly to fetch().

The request has Content-Type: application/json.

The server responds with an error status (e.g., 401 or 500).

This issue surfaces specifically on newer Node.js versions (>= v24.14.0 and probably later v25.x) where undici strictly enforces stream locking.
It appears that when Next.js receives a JSON error response, its internal patch-fetch logic attempts to read or clone the original Request object (likely for error logging, tracing, or cache evaluation). Because the stream has already been consumed by the actual network request, attempting to access it again throws this error.

This commonly affects users of wrapper libraries like openapi-fetch that construct a Request object internally and pass it to the global fetch.

Current Workarounds:

Until this is fixed in the framework, developers can use one of the following workarounds depending on their use case:

  1. Deconstruct the Request: Pass the URL and RequestInit separately instead of the Request object.
// ❌ Fails on error response
fetch(new Request(url, init)); 

// ✅ Works perfectly
fetch(url, init); 
  1. Use Native Undici Fetch: Bypass the Next.js patched fetch completely for non-GET requests by importing the native fetch: import { fetch as undiciFetch } from 'undici';

  2. Downgrade Node.js: Use Node.js <= v24.13.1 where undici's stream handling was less strict.

  3. Change Content-Type: If the API allows, using a Content-Type other than application/json seems to bypass the internal cloning logic causing the crash.


(Note: The investigation and debugging were done manually, but I used an AI assistant to help structure and translate this issue report into English.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions