Skip to main content
RapidDev - Software Development Agency
n8n-tutorial

How to Fix Unexpected Token Error When Parsing JSON from Claude in n8n

The 'Unexpected token' JSON parse error in n8n occurs when Claude wraps its JSON output in markdown code fences (```json ... ```) or adds explanatory text around it. Fix this by stripping markdown fences in a Code node before parsing, using n8n's Structured Output Parser, and adding explicit instructions in your system prompt to return raw JSON only.

What you'll learn

  • How to strip markdown code fences from Claude's JSON output in a Code node
  • How to use n8n's Structured Output Parser for automatic JSON extraction
  • How to craft system prompts that reduce Claude's tendency to wrap JSON in markdown
  • How to build a robust JSON extraction function that handles edge cases
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced9 min read15-20 minutesn8n 1.20+ with Anthropic Chat Model sub-node or HTTP Request node calling Claude APIMarch 2026RapidDev Engineering Team
TL;DR

The 'Unexpected token' JSON parse error in n8n occurs when Claude wraps its JSON output in markdown code fences (```json ... ```) or adds explanatory text around it. Fix this by stripping markdown fences in a Code node before parsing, using n8n's Structured Output Parser, and adding explicit instructions in your system prompt to return raw JSON only.

Why Claude's JSON Output Causes Parse Errors in n8n

When you ask Claude to return JSON, it often wraps the output in markdown code fences like ```json\n{...}\n``` or adds conversational text before/after the JSON. When n8n's Code node or downstream JSON-processing nodes try to parse this with JSON.parse(), the markdown fences cause a 'SyntaxError: Unexpected token' because backticks and the word 'json' are not valid JSON. This is Claude's default behavior — it formats responses for human readability. The fix involves stripping the fences before parsing and using prompt engineering to minimize the issue.

Prerequisites

  • A running n8n instance with Anthropic API credentials
  • A workflow where Claude is expected to return JSON output
  • Basic understanding of n8n Code nodes and JSON parsing

Step-by-step guide

1

Understand What Claude Actually Returns

Before fixing the issue, inspect the raw output from Claude. Add a Code node after your LLM node and log the exact response. Claude typically returns one of three formats: (1) Clean JSON with markdown fences: ```json\n{"key": "value"}\n```, (2) JSON with explanatory text: 'Here is the data:\n```json\n{"key": "value"}\n```\nLet me know if you need changes.', (3) Raw JSON without fences (rare, usually only with very explicit prompts). Understanding the format helps you write the correct extraction logic.

typescript
1// Diagnostic Code node — inspect what Claude returned
2const rawOutput = $json.text || $json.output || $json.message?.content || '';
3
4console.log('Raw output length:', rawOutput.length);
5console.log('Starts with backticks:', rawOutput.trimStart().startsWith('```'));
6console.log('Contains ```json:', rawOutput.includes('```json'));
7console.log('First 200 chars:', rawOutput.substring(0, 200));
8
9return [{ json: { raw_output: rawOutput, debug: true } }];

Expected result: You can see exactly how Claude formatted the JSON output, including any markdown fences or surrounding text.

2

Strip Markdown Fences in a Code Node

Add a Code node after your LLM node that strips markdown code fences and extracts the JSON content. This regex-based approach handles all common variations: ```json, ```, with or without language identifier, with or without surrounding text. Set the Code node to 'Run Once for Each Item'.

typescript
1const rawOutput = $json.text || $json.output || $json.message?.content || '';
2
3// Strip markdown code fences and extract JSON
4let cleaned = rawOutput;
5
6// Remove ```json ... ``` or ``` ... ``` blocks
7const codeBlockMatch = cleaned.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
8if (codeBlockMatch) {
9 cleaned = codeBlockMatch[1].trim();
10}
11
12// Try to parse the cleaned string
13try {
14 const parsed = JSON.parse(cleaned);
15 return [{ json: { data: parsed, parse_status: 'success' } }];
16} catch (e) {
17 // Fallback: try to find JSON object or array in the text
18 const jsonMatch = cleaned.match(/[\{\[][\s\S]*[\}\]]/);
19 if (jsonMatch) {
20 try {
21 const parsed = JSON.parse(jsonMatch[0]);
22 return [{ json: { data: parsed, parse_status: 'extracted' } }];
23 } catch (e2) {
24 // Still failed
25 }
26 }
27 return [{ json: { raw_text: rawOutput, parse_status: 'failed', error: e.message } }];
28}

Expected result: JSON is correctly extracted from Claude's markdown-wrapped response and available as a parsed object.

3

Use the Structured Output Parser for Automatic Extraction

n8n's Structured Output Parser node (available in AI Agent and LLM Chain workflows) automatically instructs the model to return JSON matching a schema and parses the output. Connect the Structured Output Parser sub-node to your AI Agent or Basic LLM Chain. Define your desired output schema using Zod-style definitions. The parser adds formatting instructions to the prompt automatically and handles extraction and validation of the JSON response.

typescript
1// Schema definition in the Structured Output Parser
2// Example: extracting product information
3// In the Structured Output Parser node, set the JSON Schema:
4{
5 "type": "object",
6 "properties": {
7 "product_name": { "type": "string", "description": "Name of the product" },
8 "price": { "type": "number", "description": "Price in USD" },
9 "category": { "type": "string", "description": "Product category" },
10 "features": {
11 "type": "array",
12 "items": { "type": "string" },
13 "description": "List of key features"
14 }
15 },
16 "required": ["product_name", "price", "category"]
17}

Expected result: The Structured Output Parser automatically extracts and validates JSON from Claude's response, handling markdown fences internally.

4

Optimize Your System Prompt to Reduce Markdown Wrapping

Add explicit instructions to your system prompt telling Claude not to wrap JSON in code fences. While this does not guarantee Claude will comply 100% of the time, it significantly reduces the frequency. Combine this instruction with the Code node cleanup for a robust solution.

typescript
1// System prompt additions that reduce markdown wrapping:
2
3const systemPrompt = `You are a data extraction assistant.
4
5CRITICAL OUTPUT RULES:
6- Return ONLY valid JSON. No other text.
7- Do NOT wrap the JSON in markdown code fences (no backticks).
8- Do NOT add explanations before or after the JSON.
9- Do NOT use \`\`\`json or \`\`\` markers.
10- The response must start with { or [ and end with } or ].
11
12Example correct output:
13{"name": "Example", "value": 42}
14
15Example INCORRECT output:
16Here is the JSON:
17\`\`\`json
18{"name": "Example", "value": 42}
19\`\`\`
20`;

Expected result: Claude returns raw JSON without markdown fences in most cases, with the Code node cleanup handling any remaining edge cases.

5

Add the Auto-Fixing Output Parser for Maximum Reliability

For production workflows where JSON parsing failures are unacceptable, use n8n's Auto-Fixing Output Parser. This parser wraps another output parser (like the Structured Output Parser) and, when parsing fails, automatically sends the failed output back to the LLM with instructions to fix the formatting. This adds one extra LLM call on failure but guarantees valid JSON output. Connect it as a sub-node to your AI Agent or LLM Chain.

Expected result: JSON parsing failures are automatically corrected by sending the malformed output back to Claude with fix instructions.

Complete working example

claude-json-extractor.js
1// Code node: Run Once for Each Item
2// Robust JSON extraction from Claude responses
3// Handles: markdown fences, surrounding text, escaped characters, nested JSON
4
5const rawOutput = $json.text || $json.output || $json.message?.content || '';
6
7function extractJSON(text) {
8 let cleaned = text.trim();
9
10 // Strategy 1: Remove markdown code fences
11 const fencePatterns = [
12 /```json\s*\n?([\s\S]*?)\n?\s*```/,
13 /```\s*\n?([\s\S]*?)\n?\s*```/,
14 /~~~json\s*\n?([\s\S]*?)\n?\s*~~~/,
15 /~~~\s*\n?([\s\S]*?)\n?\s*~~~/
16 ];
17
18 for (const pattern of fencePatterns) {
19 const match = cleaned.match(pattern);
20 if (match) {
21 cleaned = match[1].trim();
22 break;
23 }
24 }
25
26 // Strategy 2: Try direct parse
27 try {
28 return { data: JSON.parse(cleaned), method: 'direct' };
29 } catch (e) {
30 // Continue to next strategy
31 }
32
33 // Strategy 3: Find JSON object boundaries
34 const firstBrace = cleaned.indexOf('{');
35 const lastBrace = cleaned.lastIndexOf('}');
36 if (firstBrace !== -1 && lastBrace > firstBrace) {
37 try {
38 const substr = cleaned.substring(firstBrace, lastBrace + 1);
39 return { data: JSON.parse(substr), method: 'object_extraction' };
40 } catch (e) {
41 // Continue
42 }
43 }
44
45 // Strategy 4: Find JSON array boundaries
46 const firstBracket = cleaned.indexOf('[');
47 const lastBracket = cleaned.lastIndexOf(']');
48 if (firstBracket !== -1 && lastBracket > firstBracket) {
49 try {
50 const substr = cleaned.substring(firstBracket, lastBracket + 1);
51 return { data: JSON.parse(substr), method: 'array_extraction' };
52 } catch (e) {
53 // Continue
54 }
55 }
56
57 // Strategy 5: Fix common escaping issues
58 let fixedText = cleaned
59 .replace(/[\u2018\u2019]/g, "'") // Smart quotes
60 .replace(/[\u201C\u201D]/g, '"') // Smart double quotes
61 .replace(/\\n/g, '\\n') // Already escaped newlines
62 .replace(/(?<!\\)\n/g, '\\n'); // Unescaped newlines in strings
63
64 try {
65 return { data: JSON.parse(fixedText), method: 'character_fix' };
66 } catch (e) {
67 // All strategies failed
68 }
69
70 return null;
71}
72
73const result = extractJSON(rawOutput);
74
75if (result) {
76 return [{
77 json: {
78 data: result.data,
79 extraction_method: result.method,
80 parse_status: 'success'
81 }
82 }];
83}
84
85// Return the raw text if JSON extraction fails
86return [{
87 json: {
88 raw_text: rawOutput,
89 parse_status: 'failed',
90 suggestion: 'Add stricter JSON-only instructions to your system prompt'
91 }
92}];

Common mistakes when fixing Unexpected Token Error When Parsing JSON from Claude in n8n

Why it's a problem: Using JSON.parse() directly on Claude's output without stripping markdown fences first

How to avoid: Always run the output through a fence-stripping function before JSON.parse(). Even if it works in testing, Claude may add fences on different inputs.

Why it's a problem: Only checking for ```json fences but not plain ``` fences

How to avoid: Claude sometimes uses plain ``` without the 'json' language identifier. Check for both patterns: /```json/ and /```/.

Why it's a problem: Expecting the Structured Output Parser to work with non-AI-Agent node setups

How to avoid: The Structured Output Parser is a sub-node for AI Agent and Basic LLM Chain nodes only. For standalone OpenAI/Anthropic nodes, use a Code node for JSON extraction.

Why it's a problem: Using a simple string replace instead of regex to remove code fences

How to avoid: String replace only removes the first occurrence. Use regex with the global flag or use match() to extract the content between fences.

Best practices

  • Always add a JSON extraction Code node after LLM nodes that expect JSON output — never assume the model will return clean JSON
  • Use the Structured Output Parser when your workflow uses AI Agent or Basic LLM Chain for built-in schema validation
  • Include explicit 'no markdown fences' instructions in system prompts, with examples of correct and incorrect output
  • Add the Auto-Fixing Output Parser for mission-critical workflows where JSON parse failures are unacceptable
  • Test with varied inputs — Claude may add fences for some prompts but not others
  • Log parse failures to a database for prompt optimization: track which inputs cause formatting issues
  • Use temperature 0 when requesting structured JSON output to minimize creative formatting variations
  • Consider using Claude's native JSON mode if available through the Anthropic API's response_format parameter

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

My n8n workflow gets an 'Unexpected token' error when trying to JSON.parse the response from Claude/Anthropic. Claude wraps its JSON in markdown code fences (```json ... ```). How do I strip the fences in a Code node and also instruct Claude to return raw JSON?

n8n Prompt

Fix JSON parsing from Claude in my n8n workflow. Add a Code node after the Anthropic Chat Model that strips markdown code fences (```json and ```) from the response before parsing. Also show me how to use the Structured Output Parser sub-node as an alternative.

Frequently asked questions

Why does Claude add markdown code fences to JSON output?

Claude is trained to format responses for human readability. When it detects that it is outputting code or structured data, it wraps it in markdown code fences for visual clarity. This is helpful in chat interfaces but problematic for machine parsing in automation workflows.

Does the Structured Output Parser work with Claude in n8n?

Yes. The Structured Output Parser works with any LLM sub-node in n8n, including the Anthropic Chat Model. It adds formatting instructions to the prompt and handles JSON extraction automatically.

What if Claude returns JSON split across multiple code blocks?

This is rare but can happen with complex prompts. In this case, the regex-based extraction will only capture the first code block. Modify the extraction logic to find all code blocks and merge them, or restructure your prompt to request a single JSON object.

Is there a way to force Claude to never use markdown?

There is no API-level setting to disable markdown in Claude's responses. The most effective approach is combining explicit system prompt instructions ('Return ONLY raw JSON, no markdown') with a Code node that strips any remaining fences.

Why does JSON.parse fail on 'Unexpected token ` in JSON at position 0'?

This specific error means the JSON string starts with a backtick character (`), which is the first character of a markdown code fence (```json). The solution is to strip the code fence before parsing.

Can RapidDev help build reliable JSON extraction workflows for Claude in n8n?

Yes. RapidDev specializes in building production-grade n8n workflows with robust LLM output parsing, including multi-strategy JSON extraction, schema validation, and auto-fix retry patterns.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.