# Debugging an n8n HTTP Request That Returns _readableState Instead of JSON

![n8n Raw Body plus JSON Response stream-object debugging cover](https://www.xbstack.com/_astro/01-cover.b_DdGuVM_Z1nRJGg.webp align="center")

I first treated this as an upstream API problem. The useful change in diagnosis came from reducing the workflow to four branches against the same endpoint. Once the endpoint and payload were fixed, the Raw Body + explicit JSON combination stood out immediately. This is the project-log version of that investigation.

## 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](https://www.xbstack.com/_astro/02-four-case-control.5tBZXxQd_ZBOWOa.webp align="center")

| Case | Body Content Type | Response Format | Local n8n 1.112.4 result |
| --- | --- | --- | --- |
| A | Raw | JSON | **Stream internals returned** |
| B | JSON | JSON | Parsed JSON |
| C | Raw | Auto-detect | Parsed JSON |
| D | Raw | Text | Text wrapper |

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

```text
_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:

*   [Public GitHub reproduction](https://github.com/xbstack/my-blog-public/tree/main/github/n8n-http-request-raw-body-response-stream-repro)
    

## 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](https://www.xbstack.com/_astro/03-response-paths.DGfT-XHi_ZaatVO.webp align="center")

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:

```ts
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:

```text
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.

## 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:

```js
$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](https://www.xbstack.com/en/ai/n8n-ai-workflow-error-handling/?utm_source=hashnode&utm_medium=referral&utm_campaign=n8n_http_raw_response_stream&utm_content=related_link) 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`](https://github.com/n8n-io/n8n/blob/n8n%402.34.5/packages/nodes-base/nodes/HttpRequest/V3/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.

## Recommended production decision

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](https://www.xbstack.com/_astro/04-fix-options.CpfECqkB_Z2g8b6A.webp align="center")

> 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](https://github.com/n8n-io/n8n/issues/36402) for an upstream fix.

You can rerun the [public minimal reproduction](https://github.com/xbstack/my-blog-public/tree/main/github/n8n-http-request-raw-body-response-stream-repro) 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](https://www.xbstack.com/en/ai/n8n-webhook-production-hardening/?utm_source=hashnode&utm_medium=referral&utm_campaign=n8n_http_raw_response_stream&utm_content=related_link), [n8n Error Workflow, retry and timeout handling](https://www.xbstack.com/en/ai/n8n-ai-workflow-error-handling/?utm_source=hashnode&utm_medium=referral&utm_campaign=n8n_http_raw_response_stream&utm_content=related_link), and the [n8n Baserow parameter-dependency regression](https://www.xbstack.com/en/ai/n8n-baserow-parameter-dependencies-activation-error/?utm_source=hashnode&utm_medium=referral&utm_campaign=n8n_http_raw_response_stream&utm_content=related_link).

* * *

Canonical article and future updates: https://www.xbstack.com/en/ai/n8n-http-request-raw-body-response-stream/?utm\_source=hashnode&utm\_medium=referral&utm\_campaign=n8n\_http\_raw\_response\_stream&utm\_content=article\_body

Minimal reproduction: https://github.com/xbstack/my-blog-public/tree/main/github/n8n-http-request-raw-body-response-stream-repro

Upstream issue: https://github.com/n8n-io/n8n/issues/36402
