jackwener/OpenCLI · error · CommandExecutionError

google images returned an unexpected row shape.

Error message

google images returned an unexpected row shape.

What it means

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.

Source

Thrown at clis/google/images.js:355

function isGoogleInternalResultUrl(value) {
    try {
        const host = new URL(value).hostname.replace(/^www\./, '');
        return host === 'google.com'
            || host.endsWith('.google.com')
            || host === 'gstatic.com'
            || host.endsWith('.gstatic.com')
            || host === 'googleusercontent.com'
            || host.endsWith('.googleusercontent.com');
    } catch {
        return true;
    }
}

function normalizeImageRows(rawRows, query, limit) {
    const rows = rawRows.slice(0, limit).map((row, index) => {
        if (!Array.isArray(row)) {
            throw new CommandExecutionError('google images returned an unexpected row shape.');
        }
        const imageUrl = toHttpsUrl(row[1], 'https://www.google.com');
        const thumbnailUrl = toHttpsUrl(row[2], 'https://www.google.com');
        const sourceUrl = toHttpsUrl(row[3], 'https://www.google.com');
        if (!imageUrl || !sourceUrl || isGoogleInternalResultUrl(sourceUrl)) {
            throw new CommandExecutionError('google images returned a result row without stable external image/source identity.');
        }
        const source = String(row[4] || '').trim() || new URL(sourceUrl).hostname.replace(/^www\./, '');
        const title = String(row[0] || '').trim() || source;
        return {
            rank: index + 1,
            title,
            imageUrl,
            thumbnailUrl,
            sourceUrl,
            source,
            width: Number.isFinite(Number(row[5])) ? Number(row[5]) : null,
            height: Number.isFinite(Number(row[6])) ? Number(row[6]) : null,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run the command — transient page states often normalize on retry.
  2. Try the query in a normal browser to see if Google Images markup changed for your locale.
  3. Update/patch the extraction script in clis/google/images.js to match the new row shape.
  4. Set a stable locale/consent cookie (e.g. hl=en, CONSENT cookie) so Google serves the classic layout.

Example fix

// before
if (!Array.isArray(row)) {
  throw new CommandExecutionError('google images returned an unexpected row shape.');
}
// after
if (!Array.isArray(row)) {
  row = Array.isArray(row?.items) ? row.items : [row.title, row.img, row.thumb, row.src];
  if (!Array.isArray(row)) throw new CommandExecutionError('google images returned an unexpected row shape.');
}
Defensive patterns

Strategy: validation

Type guard

const isImageRow = (row) => Array.isArray(row) && row.length >= 4;

Try / catch

try {
  rows = await run('google images', query);
} catch (e) {
  if (/unexpected row shape/.test(e.message)) {
    rows = await run('google images', query); // retry; markup may be A/B tested
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/26152b0c91f0f3a3. Report an issue: GitHub.