Zie619/n8n-workflows · error · Error
Invalid data structure
Error message
Invalid data structure
What it means
Same strict-parser throw as errors 64-66, but in the cloned workflow 1529_Googleanalytics_Code_Automation_Webhook.json:204 ("Parse data from Google Analytics"). The node requires non-empty items whose first json has a rows array, else throws 'Invalid data structure'. Upstream is a GA4 runReport (screenPageViews/activeUsers/screenPageViewsPerUser/eventCount by unifiedScreenName); GA4 omits rows when zero rows match, which is the usual cause.
Source
Thrown at workflows/Googleanalytics/1529_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
- Open the failed execution in 1529 and read which console.log fired before the throw.
- Replace the hardcoded endDate with a dynamic {{$today}} expression in the upstream GA4 node.
- Return an empty encoded array instead of throwing when rows is missing.
- Apply the same fix to the sibling node at line 218 in this workflow, and to lines 204/218 in 1480 — they are clones.
- Point the cloned workflow at a propertyId that actually has data, or accept empty reports by design.
Example fix
// before
if (!analyticsData || !Array.isArray(analyticsData.rows)) {
throw new Error('Invalid data structure');
}
// after
if (!analyticsData || !Array.isArray(analyticsData.rows)) {
return encodeURIComponent(JSON.stringify([]));
} Defensive patterns
Strategy: validation
Validate before calling
const report = $input.all()?.[0]?.json;
if (!Array.isArray(report?.rows)) {
console.log('GA4 report without rows; keys:', Object.keys(report ?? {}), 'rowCount:', report?.rowCount);
return { json: { urlString: encodeURIComponent(JSON.stringify([])), empty: true } };
} Type guard
const isGaReport = (x) => Array.isArray(x?.rows); const isGaRow = (r) => !!r?.dimensionValues?.[0]?.value && (r?.metricValues?.length ?? 0) >= 4;
Prevention
- When cloning a workflow, immediately replace hardcoded dates with relative expressions.
- Accept zero-row reports as a normal output and branch downstream on an empty flag.
- Fix parser clones in all copies (1529 + 1480) at once to avoid divergence.
When it happens
Trigger: GA4 report for the window returns zero rows (no rows key); upstream GA node skipped/errored leaving the Code node with empty input; GA node output shape changed after an upgrade so rows sits at a different depth.
Common situations: Cloned workflow still carrying the hardcoded 2024-10-23 endDate so all post-that-date runs get empty reports; webhook firing before GA data settles for the day; property with no events in range.
Related errors
- Invalid data structure
- Invalid data structure
- Invalid row structure
- Invalid row structure
- Invalid data structure
AI-assisted analysis of Zie619/n8n-workflows@94007c1445 (2026-08-15).
Data as JSON: /api/errors/793514ee4f05b925.
Report an issue: GitHub.