jackwener/OpenCLI · error · CommandExecutionError
Gemini conversation list returned a malformed row
Error message
Gemini conversation list returned a malformed row
What it means
Thrown by CommandExecutionError when the Gemini conversation-list extraction script returns a row that is not an object with string title and url fields. The library validates every row returned by getGeminiConversationListScript inside page.evaluate before mapping it to { Title, Url }, because the sidebar DOM can yield anchors that don't carry the expected data.
Source
Thrown at clis/gemini/utils.js:1151
export async function startNewGeminiChat(page) {
await ensureGeminiPage(page);
const action = await page.evaluate(clickNewChatScript());
if (action === 'navigate') {
await page.goto(GEMINI_APP_URL, { waitUntil: 'load', settleMs: 2500 });
}
await page.wait(1);
return action;
}
export async function getGeminiConversationList(page) {
await ensureGeminiPage(page);
let rows = [];
// Gemini collapses the sidebar "最近"/Recents section by default, hiding
// the conversation anchors. Retry extraction after expanding it.
for (let attempt = 0; attempt < 3; attempt += 1) {
const raw = requireGeminiArrayResult(await page.evaluate(getGeminiConversationListScript()), 'Gemini conversation list');
rows = raw.flatMap((item) => {
if (!isObjectRecord(item) || typeof item.title !== 'string' || typeof item.url !== 'string') {
throw new CommandExecutionError('Gemini conversation list returned a malformed row');
}
if (!isGeminiConversationUrl(item.url))
return [];
return { Title: item.title, Url: item.url };
});
if (rows.length > 0)
break;
const changedRaw = unwrapGeminiEvaluateResult(await page.evaluate(expandGeminiRecentScript()), 'Gemini sidebar expand');
const changed = changedRaw === true;
// Give the React sidebar a moment to render the expanded anchors,
// longer on the first expansion (sidebar slide-in is async).
await page.wait(attempt === 0 ? 1.2 : 0.6);
if (!changed && attempt > 0)
break;
}
return rows;
}
export async function clickGeminiConversationByTitle(page, query) {View on GitHub (pinned to 49907e53dc)
Solutions
- Wait for the sidebar Recents section to finish loading (the code already retries 3x after expanding it — check whether retries were exhausted).
- Inspect one raw row returned by getGeminiConversationListScript and update the extraction script to the current sidebar DOM shape.
- Filter out placeholder/empty rows inside the in-page script before returning them.
- Wrap the call in try/catch for CommandExecutionError and degrade gracefully to an empty list.
Defensive patterns
Strategy: try-catch
Type guard
function isConversationRow(row) {
return typeof row === 'object' && row !== null &&
typeof row.title === 'string' && typeof row.url === 'string';
} Try / catch
let conversations = [];
try {
conversations = await listGeminiConversations(page);
} catch (e) {
if (String(e.message).includes('malformed row')) conversations = []; // degrade gracefully
else throw e;
} Prevention
- Only read the conversation list after the sidebar Recents section has rendered.
- Allow the library's 3-attempt expansion retry to complete before giving up.
- Update extraction selectors whenever Gemini changes the sidebar markup.
- Treat the list as best-effort data; never hard-depend on it.
When it happens
Trigger: Calling the conversation-list command when page.evaluate(getGeminiConversationListScript()) returns array entries missing title or url, or where those fields are non-strings (e.g. null entries from empty/placeholder sidebar items, sponsored rows, or a changed DOM shape).
Common situations: Gemini updated the Recents sidebar markup so the extraction script returns raw nodes instead of { title, url } objects; locale-specific sidebar entries with empty titles; mocked/partial test data; scraping while the sidebar is still loading.
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 visible turns returned a malformed row
- Gemini transcript lines returned a malformed row
- Gemini page snapshot returned a malformed result
- Gemini image detection returned a malformed result
- Gemini model discovery returned a malformed row
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2ca7fc65910e0016.
Report an issue: GitHub.