Zie619/n8n-workflows · error · Error

Invalid data structure

Error message

Invalid data structure

What it means

Thrown by the strict 'Parse data from Google Analytics' Code node (workflow 1652). Unlike the loose variant, this code validates explicitly and throws 'Invalid data structure' when: items is not a non-empty array, items[0].json is missing, or items[0].json has no Array.isArray(rows). It never falls back to an empty result — any deviation aborts the branch.

Source

Thrown at workflows/Googleanalytics/1652_Googleanalytics_Code_Automation_Webhook.json:204

              "listName": "other"
            }
          ]
        },
        "additionalFields": {}
      },
      "typeVersion": 2,
      "notes": "This googleAnalytics node performs automated tasks as part of the workflow."
    },
    {
      "id": "f8dac36b-9e8a-407f-b923-b4cea368f1bc",
      "name": "Parse data from Google Analytics",
      "type": "n8n-nodes-base.code",
      "position": [
        880,
        460
      ],
      "parameters": {
        "jsCode": "function transformToUrlString(items) {\n // Debug logging\n console.log('Input items:', JSON.stringify(items, null, 2));\n \n // Check if items is an array and has content\n if (!Array.isArray(items) || items.length === 0) {\n console.log('Items is not an array or is empty');\n throw new Error('Invalid data structure');\n }\n\n // Check if first item exists and has json property\n if (!items[0] || !items[0].json) {\n console.log('First item is missing or has no json property');\n throw new Error('Invalid data structure');\n }\n\n // Get the analytics data\n const analyticsData = items[0].json;\n \n // Check if analyticsData has rows\n if (!analyticsData || !Array.isArray(analyticsData.rows)) {\n console.log('Analytics data is missing or has no rows array');\n throw new Error('Invalid data structure');\n }\n \n // Map each row to a simplified object\n const simplified = analyticsData.rows.map(row => {\n if (!row.dimensionValues?.[0]?.value || !row.metricValues?.length) {\n console.log('Invalid row structure:', row);\n throw new Error('Invalid row structure');\n }\n \n return {\n page: row.dimensionValues[0].value,\n pageViews: parseInt(row.metricValues[0].value) || 0,\n activeUsers: parseInt(row.metricValues[1].value) || 0,\n viewsPerUser: parseFloat(row.metricValues[2].value) || 0,\n eventCount: parseInt(row.metricValues[3].value) || 0\n };\n });\n \n // Convert to JSON string and encode for URL\n return encodeURIComponent(JSON.stringify(simplified));\n}\n\n// Get input data and transform it\nconst urlString = transformToUrlString($input.all());\n\n// Return the result\nreturn { json: { urlString } };"
      },
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "ed880442-c92e-4347-b277-e8794aea6fbc",
      "name": "Parse GA data",
      "type": "n8n-nodes-base.code",
      "position": [
        1240,
        460
      ],
      "parameters": {
        "jsCode": "function transformToUrlString(items) {\n // Debug logging\n console.log('Input items:', JSON.stringify(items, null, 2));\n \n // Check if items is an array and has content\n if (!Array.isArray(items) || items.length === 0) {\n console.log('Items is not an array or is empty');\n throw new Error('Invalid data structure');\n }\n\n // Check if first item exists and has json property\n if (!items[0] || !items[0].json) {\n console.log('First item is missing or has no json property');\n throw new Error('Invalid data structure');\n }\n\n // Get the analytics data\n const analyticsData = items[0].json;\n \n // Check if analyticsData has rows\n if (!analyticsData || !Array.isArray(analyticsData.rows)) {\n console.log('Analytics data is missing or has no rows array');\n throw new Error('Invalid data structure');\n }\n \n // Map each row to a simplified object\n const simplified = analyticsData.rows.map(row => {\n if (!row.dimensionValues?.[0]?.value || !row.metricValues?.length) {\n console.log('Invalid row structure:', row);\n throw new Error('Invalid row structure');\n }\n \n return {\n page: row.dimensionValues[0].value,\n pageViews: parseInt(row.metricValues[0].value) || 0,\n activeUsers: parseInt(row.metricValues[1].value) || 0,\n viewsPerUser: parseFloat(row.metricValues[2].value) || 0,\n eventCount: parseInt(row.metricValues[3].value) || 0\n };\n });\n \n // Convert to JSON string and encode for URL\n return encodeURIComponent(JSON.stringify(simplified));\n}\n\n// Get input data and transform it\nconst urlString = transformToUrlString($input.all());\n\n// Return the result\nreturn { json: { urlString } };"
      },
      "typeVersion": 2,
      "notes": "This code node performs automated tasks as part of the workflow."
    },

View on GitHub (pinned to 94007c1445)

Solutions

  1. Run the upstream googleAnalytics node manually and inspect its output: confirm items exist and json.rows is present for the configured date range.
  2. If empty results are legitimate, return the encoded empty array instead of throwing (see exampleFix).
  3. Fix the date-range/property configuration on the GA node if the report should have data.
  4. Turn off alwaysOutputData on the GA node so empty results are visibly empty rather than a misleading empty item.

Example fix

// before
if (!analyticsData || !Array.isArray(analyticsData.rows)) {
  console.log('Analytics data is missing or has no rows array');
  throw new Error('Invalid data structure');
}

// after
if (!analyticsData || !Array.isArray(analyticsData.rows)) {
  // No data for this period is a valid outcome; downstream A.I. step handles []
  return encodeURIComponent(JSON.stringify([]));
}
Defensive patterns

Strategy: validation

Validate before calling

const items = $input.all();
const hasReport = items.length > 0 && Array.isArray(items[0]?.json?.rows);
if (!hasReport) {
  // decide: empty period -> return encodeURIComponent(JSON.stringify([]))
}

Type guard

function isGaReportItem(item) {
  return !!item?.json && Array.isArray(item.json.rows);
}

Try / catch

try { /* map rows */ } catch (e) { throw new Error(`GA parse failed for item: ${e.message}`); }

Prevention

When it happens

Trigger: The upstream googleAnalytics node returns zero items (report ran against a date range with no data), returns items whose json is empty (alwaysOutputData on an empty result), or returns the report wrapped differently than {rows: [...]}. A row-level mismatch throws the distinct 'Invalid row structure' message instead, so this error is specifically about the top-level container.

Common situations: Weekly report cron hitting a brand-new GA4 property with no events yet; date-range expression resolving to a window with zero sessions; upstream GA node erroring but alwaysOutputData emitting one empty item; template workflow pointed at a property the credentials cannot read.

Related errors


AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15). Data as JSON: /api/errors/98fa01b0d1512780. Report an issue: GitHub.