XBSTACK XBSTACK
Xiaobai

Xiaobai

Developer · Builder

Building AI engineering systems, developer tools and long-term digital assets at XBSTACK.

About Xiaobai & XBSTACK →
n8n HTTP Request Raw Body plus explicit JSON Response returning a stream object instead of parsed JSON

n8n HTTP Request Returns _readableState Instead of JSON: Raw Body Response Stream Fix

n8n HTTP Request can return _readableState instead of JSON with Raw Body + explicit JSON Response. See the four-case repro, source path and tested workarounds.

Published · 2026-08-187 min readXBSTACK
#n8n#HTTP Request#Raw Body#JSON#Stream#Debugging#Workflow

n8n HTTP Request Returns _readableState Instead of JSON: Raw Body Response Stream Fix

If an n8n HTTP Request node calls an API that normally returns JSON, but its output suddenly turns into _readableState, _writableState, bytesWritten, _events and other Node.js stream internals after you set Body Content Type = Raw and Response Format = JSON, do not start by rewriting the upstream API. On August 18, 2026, I ran four equivalent POST requests on local n8n 1.112.4. Only Raw Body + explicit JSON returned a stream-shaped object. Switching the request body to JSON, or keeping Raw while returning Response Format to Auto-detect, produced parsed responses.

I then inspected the n8n@2.34.5 tagged HttpRequestV3.node.ts. The Raw Body path still sets requestOptions.useStream = true, while the code that consumes a stream, inspects Content-Type and converts it into JSON or text sits inside autoDetectResponseFormat. That is the same failure mechanism described in n8n issue #36402, filed on August 17. One evidence boundary matters: my complete runtime control is on 1.112.4; 2.34.5 is tagged-source confirmation, not a full end-to-end run on my machine.

The fastest containment is straightforward. If your outgoing payload is ordinary JSON, change Body Content Type to JSON. If you must preserve Raw Body semantics, test Response Format = Auto-detect and validate the real endpoint. This belongs to the n8n / Workflow production troubleshooting cluster, not to ordinary application-level API debugging. The rest of this article shows the four-case control, the source path behind the behavior, which workarounds were actually tested, and what remains unverified.

First check whether this is the same failure

A normal JSON HTTP Request output should contain application fields: data, headers, json, url, or whatever the upstream response defines. If you instead see fields such as these, investigate this path first:

_readableState
_writableState
_writeState
_events
bytesWritten
_handle
_outBuffer

The question is not whether the remote server ever uses streaming internally. The question is whether n8n consumed the response stream and converted it into the JSON representation you requested.

For the control, all four HTTP Request nodes call the same https://postman-echo.com/post endpoint. Only the body type and response-format setting change. That removes most upstream variability from the comparison.

Upstream issue #36402 reports the same symptom on n8n 2.34.5: Raw request body, explicit JSON response, successful execution, but the node output contains stream internals instead of parsed JSON. The issue was assigned to the Nodes area, which makes it materially different from a generic configuration anecdote.

Four-case control: only Raw Body + explicit JSON exposed the stream object

The workflow contains one Manual Trigger and four HTTP Request branches:

Four n8n HTTP Request control cases showing Raw Body plus JSON Response returning a stream object while the other combinations return parsed JSON or text

CaseBody Content TypeResponse FormatLocal n8n 1.112.4 result
ARawJSONStream internals returned
BJSONJSONParsed JSON
CRawAuto-detectParsed JSON
DRawTextText wrapper

Case A still reports node execution success. The problem is the value shape. Its output contains:

_readableState
_writableState
bytesWritten
_handle
_outBuffer
...

That is operationally worse than a clean 400 or 500 in some workflows. Downstream expressions such as $json.id, $json.data.status, or delivery checks may simply become undefined even though the remote request itself succeeded.

Case B changes only the outgoing body type from Raw to JSON and leaves Response Format on JSON. The normal response immediately returns, including args, data, headers, json and url, with the echo marker available at json.case.

Case C keeps Raw Body but returns the response setting to Auto-detect. It also produces parsed JSON. That comparison is important: the failure is not adequately described as “Raw cannot send JSON.” The stronger hypothesis is that Raw enables a stream response, while explicit JSON skips the branch that consumes that stream.

The runnable fixture and compact result are published with the article:

Why the root cause points to useStream and autoDetectResponseFormat

The tagged n8n@2.34.5 HTTP Request V3 source contains two relevant stages.

n8n Raw Body response handling bug path versus correct path, with Auto-detect consuming the stream and explicit JSON Response exposing a stream-shaped object

During request-option construction, Auto-detect responses and file responses enable streaming. Separately, a Raw request body also enables useStream. Reduced to the important branches, the code behaves like this:

if (autoDetectResponseFormat || responseFormat === 'file') {
  requestOptions.useStream = true;
} else if (bodyContentType === 'raw') {
  requestOptions.json = false;
  requestOptions.useStream = true;
} else {
  requestOptions.json = true;
}

After the response arrives, the code under autoDetectResponseFormat inspects Content-Type and converts JSON/text streams into strings before later parsing. The conflict appears when the user explicitly selects JSON:

Raw request body
  ↓
useStream = true
  ↓
response arrives as a stream
  ↓
explicit Response Format = JSON
  ↓
autoDetectResponseFormat = false
  ↓
Auto-detect stream-consumption branch is skipped
  ↓
stream-shaped object reaches node output

This explains two otherwise surprising observations at once: why explicitly choosing JSON does not make the response more deterministic in this configuration, and why Raw + Auto-detect succeeds in the local control.

Two tested containment paths

The control produced two practical ways to get back to a consumable response without parsing stream internals yourself. They solve different request-contract constraints, so choose based on whether the outgoing body must remain byte-for-byte Raw.

Workaround 1: if the body is JSON, use JSON Body

This is the containment I would choose first. Change:

Body Content Type: Raw
Response Format: JSON

into:

Body Content Type: JSON
Response Format: JSON

That combination passed the control and returned parsed JSON.

Do not stop at a green node. Revalidate at least three things: the Content-Type received by the remote service, any serialization differences in strings/numbers/escaping, and every downstream field that used the response.

If the remote service requires exact bytes—for example a signed payload or a format that must not be re-serialized—then this workaround may change request semantics and should not be applied blindly.

Workaround 2: if Raw is mandatory, test Auto-detect

Keeping Raw Body and switching Response Format to Auto-detect also passed this control. It works here because the response enters the branch that consumes the stream and uses Content-Type to decide whether it is JSON, text or a file.

The boundary is important. Auto-detect relies on the upstream Content-Type. An API that returns JSON as text/plain, or uses different content types for success and error responses, may not behave the same way. Treat Raw + Auto-detect as a tested containment path, not an upstream fix.

Do not build a permanent parser around _outBuffer

Once you notice that the response bytes are still present somewhere under _outBuffer or _readableState.buffer, it is tempting to add a Code node, reconstruct the Buffer and call JSON.parse().

That can be useful for diagnosis, but it is a poor production contract. You would be depending on internal serialization details of Node.js streams, axios, compression and n8n execution storage rather than the documented HTTP Request output. Those shapes can change with runtime version, response size and compression behavior.

The upstream report also notes that serializing the stream object can dramatically inflate execution data relative to the actual response. The right long-term target is to restore a normal JSON/text output at the HTTP Request node boundary.

Why this can be misdiagnosed as an upstream API failure

The node can be green. There may be no HTTP 500 and no JSON parse exception. The only visible change is that application fields disappear and stream internals replace them.

Imagine the next node checks:

$json.delivery_id

It now receives undefined. A workflow may interpret that as “delivery failed” even though the remote service already accepted the request. If the automation retries side-effecting calls—payments, messages, ticket creation, order updates—that misclassification can create duplicates. The retry policy should be designed together with the site’s n8n Error Workflow, retry and timeout guide rather than replaying the request simply because an expected field vanished.

A safer debugging sequence is:

  1. Confirm the remote operation and HTTP status independently.
  2. Check whether n8n output contains stream internals.
  3. Run a JSON Body + JSON Response control.
  4. Run a Raw Body + Auto-detect control.
  5. Only then decide whether to change request semantics, keep a temporary workaround, or wait for an upstream patch.

Evidence boundary: what this test proves and what it does not

The full local workflow ran on n8n 1.112.4 and produced the four results above. I also attempted to run n8n@2.34.5 directly, but that release declares Node.js >=22.22 while the local machine had 22.18.0. Docker was installed, but its daemon was not running during this session. I did not bypass those runtime requirements merely to label the article “2.34.5 reproduced.”

For 2.34.5, I performed a separate source-level check against the tagged HttpRequestV3.node.ts and confirmed that the Raw Body useStream=true branch and Auto-detect stream-consumption structure are still present. Upstream issue #36402 supplies the 2.34.5 runtime report.

The precise evidence statement is therefore:

n8n 1.112.4 runtime reproduction + tagged n8n 2.34.5 source confirmation + upstream 2.34.5 runtime report.

When n8n ships an upstream change for #36402, the same four-case matrix should be rerun before removing any workaround.

If you are dealing with _readableState today, my order of operations is:

Three n8n stream-object troubleshooting options and the recommended debugging order: Auto-detect first, disable Raw Body when possible, and manual stream consumption only for diagnosis

The third option in the image—manually consuming the stream—is appropriate for diagnosis or temporary verification, not as a durable production contract around _readableState or _outBuffer. The production goal remains restoring normal JSON/text output at the HTTP Request node boundary.

First: if the request payload is standard JSON, move to JSON Body + JSON Response and verify the exact wire payload.

Second: if Raw must stay Raw, test Auto-detect and verify Content-Type on both success and error responses.

Third: do not permanently parse _readableState or _outBuffer, and do not blindly retry side-effecting requests just because expected response fields disappeared.

Fourth: record the n8n version, Node.js version, HTTP Request typeVersion, body type and response format, then watch n8n issue #36402 for an upstream fix.

You can rerun the public minimal reproduction without an API key. It contains one trigger and four HTTP Request branches, which is enough to determine whether your environment has the same response-processing behavior.

For adjacent production issues, see n8n Webhook Production URL, Auth and 404 troubleshooting, n8n Error Workflow, retry and timeout handling, and the n8n Baserow parameter-dependency regression.

Topic path / AI workflows

Continue through the production automation path

The workflow hub connects self-hosting, queue mode, webhooks, retries, observability and n8n implementation cases into one production-oriented learning path.

More to Explore

Topic hub →
n8n 2.35.3 $json Array Methods Return null: Reproduction and WorkaroundIn n8n 2.35.3 Edit Fields, $json.data.sort(), splice(), fill() and copyWithin() return null. Compare official 2.34.5 vs 2.35.3 Docker runs and tested copy-first workarounds.n8n 2.33.4 Baserow Workflows Fail to Activate: Fix 'Could not resolve parameter dependencies'n8n Could not resolve parameter dependencies after 2.33.4? This Baserow repro compares 2.32.7 vs 2.33.4, isolates the timezone regression, and gives safe rollback steps.n8n AI Agent Not Calling Tools: tool_choice, Provider Compatibility, and Memoryn8n AI Agent not calling tools: diagnose tool_choice, provider compatibility, tool schema and descriptions, result parsing, and memory when connected tools are skipped.n8n Error Handling: Error Workflows, Retry On Fail, Timeouts, and Failed Execution RetryHandle n8n rate limits, timeouts and node failures with Error Workflows, bounded Retry On Fail, execution history, idempotency and controlled data retention.

AI Engineering Weekly

Production changes, real failures, experiments and new XBSTACK assets.

Comments & evidence

DISCUSSION

Questions, verification and corrections

Sign in to comment. Every new comment is reviewed before publication; while pending, it is visible only to you and the administrator.

Sign-in required Reviewed before public
Loading the discussion…