{"record":{"id":"793514ee4f05b925","repo":"Zie619/n8n-workflows","slug":"invalid-data-structure-793514","errorCode":null,"errorMessage":"Invalid data structure","messagePattern":"Invalid data structure","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"workflows/Googleanalytics/1529_Googleanalytics_Code_Automation_Webhook.json","lineNumber":204,"sourceCode":"              \"listName\": \"other\"\n            }\n          ]\n        },\n        \"additionalFields\": {}\n      },\n      \"typeVersion\": 2,\n      \"notes\": \"This googleAnalytics node performs automated tasks as part of the workflow.\"\n    },\n    {\n      \"id\": \"f8dac36b-9e8a-407f-b923-b4cea368f1bc\",\n      \"name\": \"Parse data from Google Analytics\",\n      \"type\": \"n8n-nodes-base.code\",\n      \"position\": [\n        880,\n        460\n      ],\n      \"parameters\": {\n        \"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 } };\"\n      },\n      \"typeVersion\": 2,\n      \"notes\": \"This code node performs automated tasks as part of the workflow.\"\n    },\n    {\n      \"id\": \"ed880442-c92e-4347-b277-e8794aea6fbc\",\n      \"name\": \"Parse GA data\",\n      \"type\": \"n8n-nodes-base.code\",\n      \"position\": [\n        1240,\n        460\n      ],\n      \"parameters\": {\n        \"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 } };\"\n      },\n      \"typeVersion\": 2,\n      \"notes\": \"This code node performs automated tasks as part of the workflow.\"\n    },","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/Zie619/n8n-workflows/blob/94007c1445d9258a7da116646b79473e7c7c3282/workflows/Googleanalytics/1529_Googleanalytics_Code_Automation_Webhook.json#L186-L222","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nif (!analyticsData || !Array.isArray(analyticsData.rows)) {\n  throw new Error('Invalid data structure');\n}\n// after\nif (!analyticsData || !Array.isArray(analyticsData.rows)) {\n  return encodeURIComponent(JSON.stringify([]));\n}","handlingStrategy":"validation","validationCode":"const report = $input.all()?.[0]?.json;\nif (!Array.isArray(report?.rows)) {\n  console.log('GA4 report without rows; keys:', Object.keys(report ?? {}), 'rowCount:', report?.rowCount);\n  return { json: { urlString: encodeURIComponent(JSON.stringify([])), empty: true } };\n}","typeGuard":"const isGaReport = (x) => Array.isArray(x?.rows);\nconst isGaRow = (r) => !!r?.dimensionValues?.[0]?.value && (r?.metricValues?.length ?? 0) >= 4;","tryCatchPattern":null,"preventionTips":["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."],"tags":["n8n","code-node","google-analytics","ga4","empty-results","cloned-workflow"],"backgroundTag":null,"analyzedSha":"94007c1445d9258a7da116646b79473e7c7c3282","analyzedAt":"2026-08-15T04:10:37.591Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}