{"record":{"id":"064d93db29645a42","repo":"jackwener/OpenCLI","slug":"google-images-returned-a-result-row-without-stable","errorCode":null,"errorMessage":"google images returned a result row without stable external image/source identity.","messagePattern":"google images returned a result row without stable external image/source identity\\.","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/google/images.js","lineNumber":361,"sourceCode":"            || 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,\n        };\n    });\n\n    if (rows.length === 0) {\n        throw new EmptyResultError('google images', `No Google image results matched \"${query}\".`);\n    }","sourceCodeStart":343,"sourceCodeEnd":379,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/google/images.js#L343-L379","documentation":"In `normalizeImageRows`, a row that parsed as an array still failed validation: either the image URL or source URL could not be normalized to a valid https URL (`toHttpsUrl` returned falsy), or the source URL pointed to a Google-internal page (`isGoogleInternalResultUrl`). The command requires a stable external image+source identity for every row and drops the whole run otherwise.","triggerScenarios":"Calling `google images <query>` where a result row has a missing/relative/protocol-relative image href, an http-only or malformed source link, or a source URL on google.com (e.g. a Google-hosted page or link stub) that fails `isGoogleInternalResultUrl`.","commonSituations":"Google serving its new lazy-load markup where row fields shift by one index (imageUrl lands in the wrong slot); results whose thumbnails are data: URIs; google-internal 'image search' deep links appearing as source URLs; regional variants of the Images page.","solutions":["Re-run — markup-shift rows usually resolve if Google serves the stable layout on retry.","Pin a stable locale/user-agent/consent cookie so Google serves the expected Images layout.","Patch `toHttpsUrl`/`isGoogleInternalResultUrl` or the extraction script if row field positions changed.","Catch CommandExecutionError and fall back to another image search backend."],"exampleFix":"// before\nconst imageUrl = toHttpsUrl(row[1], 'https://www.google.com');\n// after (if fields shifted)\nconst imageUrl = toHttpsUrl(row[1] || row[0], 'https://www.google.com');","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"const hasStableIdentity = (row) =>\n  Array.isArray(row) &&\n  typeof row[1] === 'string' && row[1].startsWith('https://') &&\n  typeof row[3] === 'string' && row[3].startsWith('https://') &&\n  !row[3].includes('google.com');","tryCatchPattern":"try {\n  rows = await run('google images', query);\n} catch (e) {\n  if (/stable external image\\/source identity/.test(e.message)) {\n    rows = []; // or fall back to another image provider\n  } else throw e;\n}","preventionTips":["Expect google-internal URLs to be rejected by design.","Pin a stable locale/user-agent for consistent row field positions.","Fall back to a secondary image search API for robustness."],"tags":["scraping","google-images","url-validation","dom-selector"],"backgroundTag":"invalid-url-in-scraped-row","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}