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
- Update any mocked snapshot fixtures to include all five required fields with correct types.
- Re-load the page (fresh goto/ensureGeminiPage) so the current snapshot script runs completely.
- Check that page.evaluate isn't returning an error/undefined object — log the raw result before validation.
- 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
- Keep test mocks in sync with the current snapshot schema (all five fields).
- Reload the page if snapshot reads start failing after a long session.
- Log raw evaluate results when debugging to see the actual shape returned.
- Retry snapshot reads — they are cheap and idempotent.
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Gemini conversation list returned a malformed row
- Gemini visible turns returned a malformed row
- Gemini model discovery returned a malformed row
- Gemini transcript lines returned a malformed row
- Gemini image detection returned a malformed result
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/a9bea927524f92a7.
Report an issue: GitHub.