nodejs / nodejs/undici

Request with ReadableStream body causes 'expected non-null body source' assertion failure in undici 7.x

Open
#5,004 3 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
7.7k
Forks
880
Avg merge
2d 16h
Merged PRs (30d)
68

Description

Environment
  • Node.js: v24.14.0 (undici 7.21.0)
  • Platform: macOS 26.4 (Apple Silicon)
Description

In undici 7.x, creating a Request with a ReadableStream body causes an assertion failure:

Error: expected non-null body source

This is a breaking change from undici 6.x (Node 22 and earlier) where this worked fine.

Reproduction
const body = new TextEncoder().encode(JSON.stringify({ test: true }));

// Create original Request with Uint8Array body
const originalReq = new Request('https://example.com', {
  method: 'POST',
  body,
  headers: { 'Content-Type': 'application/json' }
});

// Read the body as ReadableStream
const bodyStream = originalReq.body;

// Create new Request from ReadableStream (common pattern in middleware/proxies)
const newReq = new Request(originalReq.url, {
  method: originalReq.method,
  headers: originalReq.headers,
  body: bodyStream,
  duplex: 'half',
});

// Try to fetch with the new request
await fetch(newReq);
// → Error: expected non-null body source
Root Cause

In undici/lib/web/fetch/index.js, there's an assertion:

if (request.body != null) {
  assert(request.body.source != null)
  request.body = safelyExtractBody(request.body.source)[0]
}

When a Request is created with a ReadableStream body (instead of Uint8Array, string, etc.), the body.source property is null, causing the assertion to fail.

Impact

This breaks legitimate use cases:

  • Middleware that re-creates requests (e.g., Next.js's fetch patching, proxies)
  • Libraries that create intermediate Request objects (e.g., @atproto-labs/fetch-node for SSRF protection)
Expected Behavior

Creating a Request with a ReadableStream body should work, as it did in undici 6.x (Node 22).

Workaround

Downgrade to Node.js 22 (undici 6.x) or pre-read the body as ArrayBuffer before creating the new Request.

Question

Is this strict assertion intentional? If so, what's the recommended pattern for middleware that needs to re-create Request objects?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the provided Request and ReadableStream reproduction, then inspect the assertion in lib/web/fetch/index.js and the Request/fetch flow it enters. Compare the stream case with the Uint8Array case and determine whether the assertion is intentional. Done means the behavior or recommended middleware pattern is established, with regression coverage if a code change is warranted.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.