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
Understand What Claude Actually Returns
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.
1// Diagnostic Code node — inspect what Claude returned2const rawOutput = $json.text || $json.output || $json.message?.content || '';34console.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));89return [{ 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.
Strip Markdown Fences in a Code Node
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'.
1const rawOutput = $json.text || $json.output || $json.message?.content || '';23// Strip markdown code fences and extract JSON4let cleaned = rawOutput;56// Remove ```json ... ``` or ``` ... ``` blocks7const codeBlockMatch = cleaned.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);8if (codeBlockMatch) {9 cleaned = codeBlockMatch[1].trim();10}1112// Try to parse the cleaned string13try {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 text18 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 failed25 }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.
Use the Structured Output Parser for Automatic Extraction
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.
1// Schema definition in the Structured Output Parser2// Example: extracting product information3// 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.
Optimize Your System Prompt to Reduce Markdown Wrapping
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.
1// System prompt additions that reduce markdown wrapping:23const systemPrompt = `You are a data extraction assistant.45CRITICAL 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 ].1112Example correct output:13{"name": "Example", "value": 42}1415Example INCORRECT output:16Here is the JSON:17\`\`\`json18{"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.
Add the Auto-Fixing Output Parser for Maximum Reliability
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
1// Code node: Run Once for Each Item2// Robust JSON extraction from Claude responses3// Handles: markdown fences, surrounding text, escaped characters, nested JSON45const rawOutput = $json.text || $json.output || $json.message?.content || '';67function extractJSON(text) {8 let cleaned = text.trim();910 // Strategy 1: Remove markdown code fences11 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 ];1718 for (const pattern of fencePatterns) {19 const match = cleaned.match(pattern);20 if (match) {21 cleaned = match[1].trim();22 break;23 }24 }2526 // Strategy 2: Try direct parse27 try {28 return { data: JSON.parse(cleaned), method: 'direct' };29 } catch (e) {30 // Continue to next strategy31 }3233 // Strategy 3: Find JSON object boundaries34 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 // Continue42 }43 }4445 // Strategy 4: Find JSON array boundaries46 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 // Continue54 }55 }5657 // Strategy 5: Fix common escaping issues58 let fixedText = cleaned59 .replace(/[\u2018\u2019]/g, "'") // Smart quotes60 .replace(/[\u201C\u201D]/g, '"') // Smart double quotes61 .replace(/\\n/g, '\\n') // Already escaped newlines62 .replace(/(?<!\\)\n/g, '\\n'); // Unescaped newlines in strings6364 try {65 return { data: JSON.parse(fixedText), method: 'character_fix' };66 } catch (e) {67 // All strategies failed68 }6970 return null;71}7273const result = extractJSON(rawOutput);7475if (result) {76 return [{77 json: {78 data: result.data,79 extraction_method: result.method,80 parse_status: 'success'81 }82 }];83}8485// Return the raw text if JSON extraction fails86return [{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.
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?
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.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation