jackwener/OpenCLI · error · CommandExecutionError

google images returned a result row without stable external

Error message

google images returned a result row without stable external image/source identity.

What it means

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.

Source

Thrown at clis/google/images.js:361

            || 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,
        };
    });

    if (rows.length === 0) {
        throw new EmptyResultError('google images', `No Google image results matched "${query}".`);
    }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-run — markup-shift rows usually resolve if Google serves the stable layout on retry.
  2. Pin a stable locale/user-agent/consent cookie so Google serves the expected Images layout.
  3. Patch `toHttpsUrl`/`isGoogleInternalResultUrl` or the extraction script if row field positions changed.
  4. Catch CommandExecutionError and fall back to another image search backend.

Example fix

// before
const imageUrl = toHttpsUrl(row[1], 'https://www.google.com');
// after (if fields shifted)
const imageUrl = toHttpsUrl(row[1] || row[0], 'https://www.google.com');
Defensive patterns

Strategy: try-catch

Type guard

const hasStableIdentity = (row) =>
  Array.isArray(row) &&
  typeof row[1] === 'string' && row[1].startsWith('https://') &&
  typeof row[3] === 'string' && row[3].startsWith('https://') &&
  !row[3].includes('google.com');

Try / catch

try {
  rows = await run('google images', query);
} catch (e) {
  if (/stable external image\/source identity/.test(e.message)) {
    rows = []; // or fall back to another image provider
  } else throw e;
}

Prevention

When it happens

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

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

Related errors


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