n8n JSON errors fall into a small number of repeatable buckets: LLM output that isn't clean JSON, expressions that break JSON syntax when interpolated, Code nodes returning the wrong shape, and HTTP responses that lie about their own content type. Below is what actually causes each one, the exact error text you'll see, and the fix — sourced from n8n's own docs, its community forum, and GitHub issues rather than guessed at.
The general troubleshooting approach
flowchart LR
A[Node fails] --> B[Open Input tab]
B --> C{Data matches
expected shape?}
C -->|No| D[Fix upstream node
or add expression]
C -->|Yes| E[Check JSON syntax
for stray characters]
D --> F[Re-run node]
E --> F
Click the failed node, examine its Input tab to see exactly what data it received, then compare that to what the node actually expects. Most JSON errors in n8n come down to a mismatch between those two things — missing fields, wrong data types (a string where a number is expected), empty arrays where at least one item is required, or nested structures that need flattening first. (wednesday.is)
Note
"JSON parameter needs to be valid JSON"
This is one of the most common errors reported on n8n's community forum, and it shows up almost exclusively in the HTTP Request node when the JSON body mixes static JSON with dynamic expressions. (n8n Community — JSON parameter needs to be valid JSON error)
The root cause: an expression like {{ $json.Randomized_audio }} gets inserted directly into a JSON string without escaping. If that value contains quotes or other special characters, it breaks the surrounding JSON structure. A body written like this will fail the moment the interpolated value isn't a clean, quote-free string:
{
"audioURL": {{ $json.Randomized_audio }}",
}
The trailing stray quote and unescaped content break the parser. The fix is to wrap the expression in JSON.stringify() so n8n escapes it correctly before it lands inside the JSON body:
{
"audioURL": {{ JSON.stringify($json.Randomized_audio) }}
}
(n8n Community — JSON parameter needs to be valid JSON error)
The community's other standard fixes for this error:
- Validate the JSON body in a linter (jsonlint.com) with the expressions replaced by sample values first, to confirm the static structure is sound before dynamic data ever touches it.
- Use the HTTP Request node's "Raw" JSON mode explicitly rather than mixing form-style fields with inline JSON.
- Check the expression preview to confirm what a variable actually resolves to — a
nullorundefinedvalue inserted unquoted into a JSON body will break parsing just as badly as an unescaped quote. - When possible, switch the Body tab to form/parameter mode instead of raw JSON, and let n8n handle escaping for you rather than hand-writing JSON strings with embedded expressions.
(n8n Community — JSON parameter needs to be valid JSON error)
When an LLM node is the source
JSON parse errors from an LLM's output happen when the model wraps its response in markdown code fences or adds extra text alongside the JSON — a very common LLM behavior even when explicitly instructed to return only JSON. (RapidDev — Fix JSON Parse Error from LLM Output in n8n)
A real GitHub issue against n8n describes this precisely: the AI Agent node returns the raw LLM text response instead of parsed JSON, frequently wrapped like:
```json
{"status": "qualified", "score": 82}
```
Here's your result as requested.
Calling JSON.parse($json.output) on that raw text fails immediately because of the surrounding backticks and trailing commentary. The issue also notes that field names are inconsistent between models — sometimes the text lands in $json.output, sometimes $json.text — which forces defensive coding on top of the parsing problem. The reporter says this affected 8+ production workflows, each with its own duplicated extraction logic. (GitHub n8n-io/n8n issue #27726)
Two extraction patterns are used as workarounds in practice:
Pattern A — brace matching. Find the first { and the last } (or first [ / last ] for arrays), slice the string between them, and parse that substring — ignoring any markdown fences, comments, or prose around it:
// Code node
const raw = $json.output ?? $json.text ?? '';
const start = raw.indexOf('{');
const end = raw.lastIndexOf('}');
if (start === -1 || end === -1) {
throw new Error('No JSON object found in LLM output');
}
const parsed = JSON.parse(raw.slice(start, end + 1));
return [{ json: parsed }];
Pattern B — regex-first, brace-match fallback. Strip a markdown code fence if one exists, then fall back to brace matching if it doesn't:
const raw = $json.output ?? $json.text ?? '';
const fenceMatch = raw.match(/```(?:json)?\s*([\s\S]*?)```/);
const candidate = fenceMatch ? fenceMatch[1] : raw;
const parsed = JSON.parse(candidate.trim());
return [{ json: parsed }];
Both are described in the GitHub issue as "fragile" — a minor change in how the model formats its output can break either pattern, which is why n8n's own recommendation is to not rely on ad hoc regex at all where avoidable. (GitHub n8n-io/n8n issue #27726)
The more durable fix is n8n's built-in LangChain sub-nodes rather than hand-rolled extraction:
- Structured Output Parser — enforces a JSON schema on the LLM's output. Attach it via the "Require Specific Output Format" toggle on the AI root node, which exposes an output-parser connection point. (n8n Docs — Structured Output Parser)
- Auto-fixing Output Parser — wraps another parser (typically the Structured Output Parser). If the first parse attempt fails, it calls out to a second LLM (a "retry model") specifically to repair the malformed output before returning it. (n8n Docs — Auto-fixing Output Parser)
- Code node fallback — as a last line of defense, strip fences and validate with
JSON.parsein a Code node after the parser sub-nodes, per RapidDev's writeup. (RapidDev — Fix JSON Parse Error from LLM Output in n8n)
Warning
The n8n docs also flag a second gotcha specific to these sub-nodes: expressions inside a sub-node don't resolve per item the way they do in standard nodes. An expression like {{ $json.name }} fed to several input items will consistently resolve to the first item's value only, not iterate across all of them — a frequent source of confusion when a parser's output looks static across a batch. (n8n Docs — Structured Output Parser common issues)
One more forum thread worth noting: users running the JSON/Structured Output Parser specifically against Anthropic models report it "not working" or throwing "Unexpected Token" errors more often than with OpenAI models, tracked back to Claude's tendency to add explanatory preamble even under strict system-prompt instructions — which is exactly the failure mode the Auto-fixing Output Parser's retry-model pattern is designed to catch. (n8n Community — JSON output parser not working for Anthropic LLM)
"Invalid JSON" from unexpected characters
Happens when data passed between nodes isn't formatted correctly — unexpected characters or missing brackets in the structure. Running the data through a JSON validator/formatter before it's processed catches this before it breaks the workflow. (wednesday.is)
In practice this usually traces back to one of:
- Trailing commas left over from string concatenation instead of proper object construction.
- Smart quotes (
"") pasted in from a document editor instead of straight quotes ("), whichJSON.parserejects outright. - Control characters (literal newlines, tabs) embedded in a string value without escaping — common when LLM output or scraped web text is dropped straight into a JSON field.
"Cannot read properties of undefined" errors
This is a distinct error family from JSON parse failures — it's a runtime error, not a syntax error, and it means the workflow successfully got some data but not the shape a downstream node expected. It shows up repeatedly across n8n's community forum and GitHub issues in slightly different forms: reading 'name', reading 'length', reading 'content', reading '0', and reading 'node'. (n8n Community forum search results)
Reported patterns include: a Respond to Webhook node throwing this error when receiving JSON from a Code node further upstream in a complex execution path; a Form node throwing it when a date field is defined via the "using JSON" option; and Function/Code nodes throwing it when trying to index into an array (reading '0') that came back empty instead of populated. (GitHub n8n-io/n8n issue #16588)
The fix pattern is the same regardless of which property name shows up in the error: don't assume a nested path exists. Guard it:
// Broken — throws if items[0].json.data.value is missing at any level
const value = items[0].json.data.value;
// Fixed — optional chaining with a fallback
const value = items[0]?.json?.data?.value ?? null;
if (value === null) {
// handle the missing-data case explicitly instead of crashing downstream
}
The sneaky HTTP Content-Type issue
When an API returns valid JSON but sets the wrong Content-Type header (text/plain instead of application/json), n8n passes the response through as a raw string instead of a parsed object — looking like a JSON error when the actual data was fine. Fix: in the HTTP Request node settings, explicitly set Response Format to "JSON," which forces parsing regardless of what Content-Type header the API sent. (RapidDev — Fix JSON Parse Error from LLM Output in n8n)
This is worth checking first whenever a node downstream of an HTTP Request throws a JSON error but the API's response looks fine when you paste it into a browser or Postman — the data was never broken, n8n just never parsed it.
Code node data structure
All data passed between n8n nodes is an array of objects — a Code node that returns data in a different shape (a bare object, a plain string) will fail downstream, even if the code itself ran without error. (RapidDev — Fix JSON Parse Error from LLM Output in n8n)
// Broken — returns a bare object, not the array-of-{json:...} shape n8n expects
return { status: 'ok', total: 42 };
// Fixed
return [{ json: { status: 'ok', total: 42 } }];
If a node is processing multiple input items and needs to return multiple output items, each one needs its own { json: ... } wrapper inside the array:
return items.map(item => ({
json: {
...item.json,
processed: true,
},
}));
Tip
console.log(JSON.stringify(returnValue, null, 2)) line right before the return, run the node once, and read the execution log. If it isn't [{ "json": {...} }, ...], downstream nodes will fail.
A layered defense, not a single fix
No single fix here is a complete answer on its own — the pattern that actually holds up in production, per RapidDev's multi-layered approach, is stacking defenses: schema enforcement via the Structured Output Parser, automatic repair via the Auto-fixing Output Parser, explicit system-prompt instructions telling the model to return JSON only, and a Code node fallback that strips fences and validates before anything downstream trusts the data. (RapidDev — Get Consistent JSON from LLMs in n8n)
Treat each layer as catching what the one before it missed, not as redundant — LLM output formatting is inconsistent enough, and n8n's own expression-resolution quirks inside sub-nodes are sharp enough, that any single safeguard will eventually let something malformed through.
Sources: RapidDev — Fix JSON Parse Error from LLM Output in n8n, RapidDev — Get Consistent JSON from LLMs in n8n, Wednesday Solutions — n8n Troubleshooting: Common Issues and Solutions, n8n Community — JSON parameter needs to be valid JSON error, n8n Community — Cannot read properties of undefined (reading 'name'), n8n Community — JSON output parser not working for Anthropic LLM, GitHub n8n-io/n8n Issue #27726 — AI Agent node JSON output buried in raw text, GitHub n8n-io/n8n Issue #16588 — Cannot read properties of undefined (reading 'name'), n8n Docs — Structured Output Parser, n8n Docs — Structured Output Parser common issues, n8n Docs — Auto-fixing Output Parser
Get new posts as they publish
No spam — just the next post, straight to your inbox.