JSON parsing error in n8n contact extractor workflow

I’m encountering a malformed JSON error in my n8n automation

I’ve developed a contact extraction system in n8n that retrieves business leads and inputs them into Google Sheets. The primary workflow invokes a subworkflow, yet I’m facing this error:

The ‘JSON Output’ in item 0 contains invalid JSON.

This problem arises in the JSON processing node within my subworkflow. I’m attempting to gather contact information from a data scraping API and automatically fill my spreadsheet.

Setup of the main workflow:

{
  "name": "contactExtractor",
  "nodes": [
    {
      "parameters": {
        "name": "contactScraping",
        "description": "=Utilize this function to gather contacts when your search criteria is complete.\n\nThe input format must be:\n\n[\n  {\n    \"region\": [\n      \"REGION1+HERE\",\n      \"REGION2+HERE\"\n    ],\n    \"company_type\": [\n      \"TYPE1+HERE\",\n      \"TYPE2+HERE\"\n    ],\n    \"position\": [\n      \"ROLE1+HERE\",\n      \"ROLE2+HERE\"\n    ]\n  }\n]",
        "workflowId": {
          "__rl": true,
          "value": "9xyz3WIetP7d1KBc",
          "mode": "list",
          "cachedResultName": "Contact Sub-Workflow"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [120, 200],
      "id": "c891a514-fc69-4b5b-b545-abc123456",
      "name": "contactScraping"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.message.text }}",
        "options": {
          "systemMessage": "=# Role\nYou are a contact extraction assistant.\n\n# Available Tools\n### contactScraping:\nExtract business contacts and save to spreadsheet.\n\n# Guidelines\n- Request clarification when necessary\n- Collect location, type of company, and job roles\n- Substitute spaces with '+' in queries\n- Present yourself as Contact Assistant\n\n# Example Interaction\n- User: \"Hello\"\n- Assistant: \"Hi! I'm your Contact Assistant. What kind of contacts would you like to find today?\"\n- User gives their criteria\n- Call contactScraping with the correct JSON format"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [-150, -40],
      "id": "xyz123-agent",
      "name": "Contact Agent"
    }
  ]
}

Configuration of the subworkflow:

{
  "name": "Contact Sub-Workflow",
  "nodes": [
    {
      "parameters": {
        "url": "https://api.extractor.com/v2/business-scraper/runs",
        "sendBody": true,
        "jsonBody": "={\n    \"getEmails\": true,\n    \"getPhones\": true,\n    \"maxResults\": 300,\n    \"searchUrl\": \"{{ $json.searchURL }}\"\n}",
        "authentication": "genericCredentialType"
      },
      "type": "n8n-nodes-base.httpRequest",
      "position": [-300, 180],
      "id": "scraper-node",
      "name": "Business Scraper"
    },
    {
      "parameters": {
        "mode": "raw",
        "jsonOutput": "={\n\"searchCriteria\":\n{{ $json.searchCriteria }}\n}"
      },
      "type": "n8n-nodes-base.set",
      "position": [-650, 180],
      "id": "json-processor",
      "name": "JSON"
    }
  ]
}

The aim is for extracted contacts to be automatically added to my Google Sheet. Any thoughts on what might be triggering the JSON parsing issue?

Found your problem. The JSON in your SET node is broken - you’re not handling the variable correctly.

This line’s the issue:

"searchCriteria":
{{ $json.searchCriteria }}

You need quotes around the variable and no line break:

"searchCriteria": "{{ $json.searchCriteria }}"

Honestly though? After years of fighting n8n’s JSON parsing, I’d just switch to Latenode. Way less headache.

Just migrated a contact extraction system there - total game changer. No more cryptic JSON errors or wrestling with expressions. Their data transformation actually works.

You could rebuild your whole contact scraping setup with better error handling and cleaner flow. Plus their Google Sheets integration doesn’t randomly break.

Worth checking out: https://latenode.com

Your JSON processor node has a line break inside the JSON structure, and n8n’s expression parser can’t handle that. Remove the line break and format it as one line:

{
  "searchCriteria": {{ $json.searchCriteria }}
}

Throw a debug node before the JSON processor to see what’s actually in $json.searchCriteria. I’ve seen variables with unescaped quotes or weird characters that break JSON parsing. If searchCriteria’s already a JSON object, you’ll need to stringify it first with JSON.stringify() in a code node. Also check that your Business Scraper node’s returning valid JSON - sometimes APIs spit out HTML error pages when auth fails, which breaks everything downstream.

your json syntax is broken in the set node. you’re missing a comma or quote in that jsonOutput expression. wrap the whole thing in proper quotes and check if $json.searchCriteria is returning valid data - it might be undefined.

That malformed JSON error is happening because your SET node isn’t handling expressions properly. When you use {{ $json.searchCriteria }} without stringifying it first, n8n tries to inject raw data that might have unescaped characters or nested objects - and that breaks your JSON structure.

I’ve hit this exact issue building lead gen workflows. Fix it by using JSON.stringify() to handle the escaping properly. Change your jsonOutput parameter to:

{
  "searchCriteria": {{ JSON.stringify($json.searchCriteria) }}
}

This handles edge cases where searchCriteria has quotes, backslashes, or complex nested data from your scraping API. Also check that your Business Scraper node always returns JSON responses - auth failures often return HTML error pages that mess up the whole workflow downstream.