HTTP 200 but JSON parsing fails: six local diagnostic cases for API workflows

An HTTP Request node can reach a server successfully and still receive something that cannot be parsed as JSON. Before changing expressions downstream, separate three observations: the status, the declared media type, and the actual body.

I made a small, reproducible Python fixture to make those differences visible. Both scripts and their measured output are in this diagnostic walkthrough. They use the standard library and temporary localhost fixtures; no API key or external service is needed.

What the six cases show

Controlled case Observation What it establishes
200 + valid JSON JSON object decoded Parsing succeeded; required application fields still need validation.
200 + HTML Non-JSON media type Inspect the endpoint and authentication flow; HTML alone does not prove a particular cause.
503 + JSON error body HTTP failure A readable JSON error is still a failed HTTP response.
200 + JSON media type + broken body Parsing fails A Content-Type header is a claim, not validation of the bytes.
Connection refused No HTTP status exists The connection failed before an HTTP response.
200 headers, body deliberately withheld Body read times out Receiving headers does not prove the body finished arriving.

Applying the distinction to an n8n investigation

For an isolated diagnostic request, the HTTP Request node documentation describes Include Response Headers and Status and a Text response format. These let you inspect the response before assuming it is JSON. Changing the output format also changes what downstream nodes receive, so use a test copy with downstream actions disconnected.

Record the status if there is one, Content-Type, the failure phase, and a short redacted body excerpt where appropriate. If the body is HTML, inspect the expected endpoint and redirects. If it is a 503 response, investigate availability and the API’s retry guidance. If declared JSON is malformed, retain a safe example for the producer. Avoid swallowing every failure into an empty object: that loses the evidence needed to distinguish the cases.

The documentation also describes Never Error, which changes handling of HTTP status codes. It does not turn a failed business operation into a successful one. Do not use it as proof that a request worked.

Reproduce and interpret carefully

Save the two scripts from the walkthrough as http_json_demo.py and http_transport_demo.py, then run each with Python 3. The first asserts four response cases; the second asserts a refused connection and a delayed body. The transport fixture was run on macOS with Python 3.12.3. Its short timeout is a deliberate test setting, not a production recommendation.

These are executed Python fixtures. The n8n settings above are documentation-based guidance; I have not validated this fixture inside an n8n workflow. In particular, the Python body-read timeout is not a claim about n8n’s timeout semantics. The scripts start and stop their own test servers; they are not persistent URLs to paste into n8n Cloud or Docker.

Keep credentials and real customer payloads out of public screenshots or replies. A sanitized failure phase, status and media type are usually a more useful starting point than only β€œJSON parsing failed.”

1 Like