jackwener/OpenCLI · error · CommandExecutionError

Gemini page snapshot returned a malformed result

Error message

Gemini page snapshot returned a malformed result

What it means

Thrown by readGeminiSnapshot when the snapshot object returned by readGeminiSnapshotScript lacks the required shape: turns and transcriptLines arrays, and boolean composerHasText, isGenerating, and structuredTurnsTrusted fields. The library uses this snapshot for submission detection, so a malformed result would silently break polling logic; it fails fast instead.

Source

Thrown at clis/gemini/utils.js:1234

export async function getLatestGeminiAssistantResponse(page) {
    await ensureGeminiPage(page);
    const turns = await getGeminiVisibleTurns(page);
    const assistantTurn = [...turns].reverse().find((turn) => turn.Role === 'Assistant');
    if (assistantTurn?.Text) {
        return sanitizeGeminiResponseText(assistantTurn.Text, '');
    }
    const lines = await getGeminiTranscriptLines(page);
    return lines.join('\n').trim();
}
export async function readGeminiSnapshot(page) {
    await ensureGeminiPage(page);
    const snapshot = requireGeminiObjectResult(await page.evaluate(readGeminiSnapshotScript()), 'Gemini page snapshot');
    if (!Array.isArray(snapshot.turns) ||
        !Array.isArray(snapshot.transcriptLines) ||
        typeof snapshot.composerHasText !== 'boolean' ||
        typeof snapshot.isGenerating !== 'boolean' ||
        typeof snapshot.structuredTurnsTrusted !== 'boolean') {
        throw new CommandExecutionError('Gemini page snapshot returned a malformed result');
    }
    return snapshot;
}
function findLastUserTurnIndex(turns) {
    for (let index = turns.length - 1; index >= 0; index -= 1) {
        if (turns[index]?.Role === 'User')
            return index;
    }
    return null;
}
function findLastUserTurn(turns) {
    const index = findLastUserTurnIndex(turns);
    return index === null ? null : turns[index] ?? null;
}
export async function waitForGeminiSubmission(page, before, timeoutSeconds) {
    const preSendAssistantCount = before.turns.filter((turn) => turn.Role === 'Assistant').length;
    const maxPolls = Math.max(1, Math.ceil(timeoutSeconds));
    for (let index = 0; index < maxPolls; index += 1) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Update any mocked snapshot fixtures to include all five required fields with correct types.
  2. Re-load the page (fresh goto/ensureGeminiPage) so the current snapshot script runs completely.
  3. Check that page.evaluate isn't returning an error/undefined object — log the raw result before validation.
  4. Catch CommandExecutionError and retry the snapshot read with backoff.

Example fix

// before (test mock)
{ turns: [], transcriptLines: [], composerHasText: false, isGenerating: false }
// after
{ turns: [], transcriptLines: [], composerHasText: false, isGenerating: false, structuredTurnsTrusted: true }
Defensive patterns

Strategy: validation

Validate before calling

// validate a hand-built snapshot before passing it into helpers
function isValidSnapshot(s) {
  return !!s && Array.isArray(s.turns) && Array.isArray(s.transcriptLines) &&
    typeof s.composerHasText === 'boolean' && typeof s.isGenerating === 'boolean' &&
    typeof s.structuredTurnsTrusted === 'boolean';
}

Type guard

function isGeminiSnapshot(s) {
  return typeof s === 'object' && s !== null && Array.isArray(s.turns) &&
    Array.isArray(s.transcriptLines) && typeof s.composerHasText === 'boolean' &&
    typeof s.isGenerating === 'boolean' && typeof s.structuredTurnsTrusted === 'boolean';
}

Try / catch

let snapshot;
try {
  snapshot = await readGeminiSnapshot(page);
} catch (e) {
  if (String(e.message).includes('malformed result')) { await page.wait(1); snapshot = await readGeminiSnapshot(page); }
  else throw e;
}

Prevention

When it happens

Trigger: Any snapshot read (used by waitForGeminiSubmission, isGeminiGenerating flows, sendGeminiMessage) where page.evaluate returns an object missing/incorrectly-typed fields — e.g. the in-page script threw partially and returned an error stub, or the script version in the page predates a new field like structuredTurnsTrusted.

Common situations: Mixing library versions or cached page scripts that return older snapshot shapes; evaluate result unwrapping producing undefined fields; Gemini page in an error state where the snapshot script bails early; tests with hand-written snapshot mocks missing new fields.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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