{"record":{"id":"26152b0c91f0f3a3","repo":"jackwener/OpenCLI","slug":"google-images-returned-an-unexpected-row-shape","errorCode":null,"errorMessage":"google images returned an unexpected row shape.","messagePattern":"google images returned an unexpected row shape\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/google/images.js","lineNumber":355,"sourceCode":"\nfunction isGoogleInternalResultUrl(value) {\n    try {\n        const host = new URL(value).hostname.replace(/^www\\./, '');\n        return host === 'google.com'\n            || host.endsWith('.google.com')\n            || host === 'gstatic.com'\n            || host.endsWith('.gstatic.com')\n            || host === 'googleusercontent.com'\n            || host.endsWith('.googleusercontent.com');\n    } catch {\n        return true;\n    }\n}\n\nfunction normalizeImageRows(rawRows, query, limit) {\n    const rows = rawRows.slice(0, limit).map((row, index) => {\n        if (!Array.isArray(row)) {\n            throw new CommandExecutionError('google images returned an unexpected row shape.');\n        }\n        const imageUrl = toHttpsUrl(row[1], 'https://www.google.com');\n        const thumbnailUrl = toHttpsUrl(row[2], 'https://www.google.com');\n        const sourceUrl = toHttpsUrl(row[3], 'https://www.google.com');\n        if (!imageUrl || !sourceUrl || isGoogleInternalResultUrl(sourceUrl)) {\n            throw new CommandExecutionError('google images returned a result row without stable external image/source identity.');\n        }\n        const source = String(row[4] || '').trim() || new URL(sourceUrl).hostname.replace(/^www\\./, '');\n        const title = String(row[0] || '').trim() || source;\n        return {\n            rank: index + 1,\n            title,\n            imageUrl,\n            thumbnailUrl,\n            sourceUrl,\n            source,\n            width: Number.isFinite(Number(row[5])) ? Number(row[5]) : null,\n            height: Number.isFinite(Number(row[6])) ? Number(row[6]) : null,","sourceCodeStart":337,"sourceCodeEnd":373,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/google/images.js#L337-L373","documentation":"In `normalizeImageRows` of the `google images` command, each raw row from the in-page extraction script must be an array (title, imageUrl, thumbnailUrl, sourceUrl, ...). A CommandExecutionError is thrown when a row is not an array, meaning Google's page markup shifted and the extraction script returned data in an unexpected shape.","triggerScenarios":"Calling `google images <query>` where the page's inline dataset rows are no longer plain arrays — Google Images layout/marker-data changes, a CAPTCHA/consent page partially matching the extraction script, or rows serialized as objects instead of arrays.","commonSituations":"Google rolling out a new Images result markup; scraping during an A/B test; automation driving an unexpected locale (e.g. consent interstitial in EU) that feeds malformed rows into the parser.","solutions":["Re-run the command — transient page states often normalize on retry.","Try the query in a normal browser to see if Google Images markup changed for your locale.","Update/patch the extraction script in clis/google/images.js to match the new row shape.","Set a stable locale/consent cookie (e.g. hl=en, CONSENT cookie) so Google serves the classic layout."],"exampleFix":"// before\nif (!Array.isArray(row)) {\n  throw new CommandExecutionError('google images returned an unexpected row shape.');\n}\n// after\nif (!Array.isArray(row)) {\n  row = Array.isArray(row?.items) ? row.items : [row.title, row.img, row.thumb, row.src];\n  if (!Array.isArray(row)) throw new CommandExecutionError('google images returned an unexpected row shape.');\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":"const isImageRow = (row) => Array.isArray(row) && row.length >= 4;","tryCatchPattern":"try {\n  rows = await run('google images', query);\n} catch (e) {\n  if (/unexpected row shape/.test(e.message)) {\n    rows = await run('google images', query); // retry; markup may be A/B tested\n  } else throw e;\n}","preventionTips":["Pin locale/consent cookies so Google serves the stable Images layout.","Retry once before surfacing the error.","Track Google Images markup changes if you script this often."],"tags":["scraping","google-images","payload-shape","dom-selector"],"backgroundTag":"unexpected-payload-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}