jackwener/OpenCLI · error · CommandExecutionError

Gemini transcript lines returned a malformed row

Error message

Gemini transcript lines returned a malformed row

What it means

Thrown by getGeminiTranscriptLines when requireGeminiArrayResult succeeds but the returned array contains non-string entries. The transcript-lines script must yield an array of plain strings; any object, null, or number in the array triggers this CommandExecutionError.

Source

Thrown at clis/gemini/utils.js:1201

    const lines = await getGeminiTranscriptLines(page);
    return lines.map((line) => ({ Role: 'System', Text: line }));
}
async function getGeminiStructuredTurns(page) {
    await ensureGeminiPage(page);
    const raw = requireGeminiArrayResult(await page.evaluate(getTurnsScript()), 'Gemini visible turns');
    for (const turn of raw) {
        if (!isObjectRecord(turn) || typeof turn.Role !== 'string' || typeof turn.Text !== 'string') {
            throw new CommandExecutionError('Gemini visible turns returned a malformed row');
        }
    }
    const turns = collapseAdjacentGeminiTurns(raw);
    return Array.isArray(turns) ? turns : [];
}
export async function getGeminiTranscriptLines(page) {
    await ensureGeminiPage(page);
    const lines = requireGeminiArrayResult(await page.evaluate(getTranscriptLinesScript()), 'Gemini transcript lines');
    if (!lines.every((line) => typeof line === 'string')) {
        throw new CommandExecutionError('Gemini transcript lines returned a malformed row');
    }
    return lines;
}
export async function waitForGeminiTranscript(page, attempts = 5) {
    let lines = [];
    for (let index = 0; index < attempts; index += 1) {
        lines = await getGeminiTranscriptLines(page);
        if (lines.length > 0)
            return lines;
        if (index < attempts - 1)
            await page.wait(1);
    }
    return lines;
}
export async function getLatestGeminiAssistantResponse(page) {
    await ensureGeminiPage(page);
    const turns = await getGeminiVisibleTurns(page);
    const assistantTurn = [...turns].reverse().find((turn) => turn.Role === 'Assistant');

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry after a short wait for the transcript to finish rendering.
  2. Inspect raw output of getTranscriptLinesScript and coerce/map entries to strings inside the in-page script (e.g. el.textContent.trim()).
  3. Filter out null/undefined entries in the extraction script before returning.
  4. Catch CommandExecutionError and fall back to the structured-turns API instead.
Defensive patterns

Strategy: type-guard

Type guard

function isStringArray(v) {
  return Array.isArray(v) && v.every((x) => typeof x === 'string');
}

Try / catch

try {
  lines = await getGeminiTranscriptLines(page);
} catch (e) {
  if (String(e.message).includes('malformed row')) lines = [];
  else throw e;
}

Prevention

When it happens

Trigger: Calling transcript-line extraction when getTranscriptLinesScript() returns mixed content (e.g. nested elements serialized as objects, undefined for empty line containers) because Gemini's transcript DOM changed or the page was polled mid-render.

Common situations: Gemini update changing line container structure; transcript containing rich nodes (images/code) that the script maps to objects; stale page snapshot from before hydration; mocked data of the wrong shape.

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/cf306c2296613824. Report an issue: GitHub.