{"record":{"id":"4e8cc2c6232a34fd","repo":"Zie619/n8n-workflows","slug":"invalid-data-structure-4e8cc2","errorCode":null,"errorMessage":"Invalid data structure","messagePattern":"Invalid data structure","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"workflows/Googleanalytics/0475_Googleanalytics_Code_Automate_Scheduled.json","lineNumber":527,"sourceCode":"      \"credentials\": {\n        \"googleAnalyticsOAuth2\": {\n          \"id\": \"8OdVzOGJqhJ3ti8k\",\n          \"name\": \"KBB Google Analytics account\"\n        }\n      },\n      \"typeVersion\": 2,\n      \"notes\": \"This googleAnalytics node performs automated tasks as part of the workflow.\"\n    },\n    {\n      \"id\": \"15f3edcb-2e31-4faa-8db2-62da69bbfe8d\",\n      \"name\": \"Parse - Get Page Engagement This Week\",\n      \"type\": \"n8n-nodes-base.code\",\n      \"position\": [\n        1040,\n        740\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\": \"46cd21cd-c7f4-45cb-a724-db8a122f9de3\",\n      \"name\": \"Parse - Get Page Engagement Prior Week\",\n      \"type\": \"n8n-nodes-base.code\",\n      \"position\": [\n        1440,\n        740\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    // Filter out invalid rows and map each valid row to a simplified object\\n    const simplified = analyticsData.rows\\n        .filter(row => {\\n            // Check if row is valid and its properties exist\\n            const isValid = row \\n                && row.dimensionValues \\n                && row.dimensionValues[0] \\n                && row.dimensionValues[0].value \\n                && row.metricValues \\n                && row.metricValues.length > 0;\\n            \\n            if (!isValid) {\\n                console.log('Ignoring invalid or null row:', row);\\n            }\\n            return isValid;\\n        })\\n        .map(row => ({\\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    // 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      },\n      \"typeVersion\": 2,\n      \"notes\": \"This code node performs automated tasks as part of the workflow.\"\n    },","sourceCodeStart":509,"sourceCodeEnd":545,"githubUrl":"https://github.com/Zie619/n8n-workflows/blob/94007c1445d9258a7da116646b79473e7c7c3282/workflows/Googleanalytics/0475_Googleanalytics_Code_Automate_Scheduled.json#L509-L545","documentation":"Thrown by 'Parse - Get Page Engagement This Week' in a Google Analytics 4 reporting workflow. The node validates the upstream GoogleAnalytics node output: items must be a non-empty array, items[0].json must exist, and analyticsData.rows must be an array. 'Invalid data structure' covers all three failures; the console.log lines in the execution pinpoint which check tripped.","triggerScenarios":"The GA4 runReport response has no rows key (GA4 omits rows entirely when the report is empty — a week with zero traffic), the GoogleAnalytics node returned an error object instead of a report (bad property ID, expired credentials), or items came back empty.","commonSituations":"New/low-traffic GA4 property with no events in the date range (rows is undefined, not an empty array — this is the classic GA4 gotcha); service account credentials expired or property ID misconfigured; date-range expressions in the trigger producing empty windows.","solutions":["Check the execution log for which console.log line fired ('no rows array' vs 'not an array or empty') to identify the exact failure.","Test the upstream GoogleAnalytics node directly — verify property ID, credentials, and that the date range contains data.","Treat a missing rows key as an empty report: const rows = analyticsData.rows ?? []; and skip downstream AI/report steps when empty.","For genuinely empty weeks, add an IF branch that exits gracefully instead of throwing."],"exampleFix":"// before\nif (!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// after (GA4 omits rows when the report is empty)\nif (!analyticsData || typeof analyticsData !== 'object') {\n    throw new Error(`Invalid data structure: ${JSON.stringify(analyticsData).slice(0, 200)}`);\n}\nconst rows = Array.isArray(analyticsData.rows) ? analyticsData.rows : []; // empty week, not an error","handlingStrategy":"validation","validationCode":"const j = items[0]?.json;\nconst ok = Boolean(j) && (Array.isArray(j.rows) || j.rows === undefined); // GA4 omits rows when empty\nconst rows = j?.rows ?? [];","typeGuard":"function isGa4Report(j) {\n  return Boolean(j && typeof j === 'object' && !j.error && (Array.isArray(j.rows) || !('rows' in j)));\n}","tryCatchPattern":null,"preventionTips":["Treat a missing rows key as an empty report — GA4 omits it, it is not an error.","Branch on empty data (IF node) and skip the AI/report step instead of throwing.","Check the analytics node for error objects (j.error / j.code) and fail with their message.","Log which guard tripped (the node already does) and read it before changing code."],"tags":["n8n","google-analytics","ga4","empty-response","code-node"],"backgroundTag":null,"analyzedSha":"94007c1445d9258a7da116646b79473e7c7c3282","analyzedAt":"2026-08-15T04:10:37.591Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}