jackwener/OpenCLI · error · CommandExecutionError
Gmail batch-view returned a thread without an id at index ${
Error message
Gmail batch-view returned a thread without an id at index ${index} What it means
parseBatchView extracts the thread id from record[3] (stripping a leading '#'); if the cleaned value is empty it throws this CommandExecutionError naming the row index. A thread record without an id cannot be addressed by later commands (open/reply), so the library refuses to return a row it cannot key. This usually means the record's field layout shifted or the row is a placeholder.
Source
Thrown at clis/gmail/utils.js:147
.flatMap((message) => Array.isArray(message?.[10]) ? message[10] : [])
.filter((label) => typeof label === 'string' && label.startsWith('^')))];
}
export function parseBatchView(body) {
if (!Array.isArray(body) || body.length !== 19) {
throw new CommandExecutionError('Gmail batch-view response had an unexpected shape');
}
const rows = Array.isArray(body[2]) ? body[2] : [];
return rows.map((wrapper, index) => {
const record = Array.isArray(wrapper?.[0]) ? wrapper[0] : null;
if (!record || record.length < 5) {
throw new CommandExecutionError(`Gmail batch-view returned a malformed thread at index ${index}`);
}
const threadId = cleanString(record[3]).replace(/^#/, '');
const messages = Array.isArray(record[4]) ? record[4] : [];
const latest = messages.at(-1);
const sender = senderFromSummary(latest);
if (!threadId) throw new CommandExecutionError(`Gmail batch-view returned a thread without an id at index ${index}`);
const labels = labelIdsFromMessages(messages);
return {
threadId,
subject: cleanString(record[0]) || '(no subject)',
from: sender?.address || null,
fromName: sender?.name || null,
snippet: cleanString(record[1]) || null,
messageCount: messages.length,
unread: labels.includes('^u'),
starred: labels.includes('^t'),
date: gmailDate(record[2], `thread ${threadId}`),
labels,
};
});
}
function labelCounts(value) {
const result = new Map();View on GitHub (pinned to 49907e53dc)
Solutions
- Retry the command — concurrent edits to threads during the search can produce transient id-less rows.
- Update opencli to match the current Gmail record layout if the error is reproducible.
- Narrow the query to avoid the affected thread (e.g. exclude drafts: -in:drafts).
- Reload Gmail and rerun to get a fresh, consistent batch-view payload.
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
function hasThreadId(record) {
return typeof record?.[3] === 'string' && record[3].trim().length > 0;
} Try / catch
try {
threads = await gmailSearch(query);
} catch (error) {
if (String(error.message).includes('thread without an id')) {
await sleep(1500); // let in-flight sync placeholders resolve
threads = await gmailSearch(query);
} else throw error;
} Prevention
- Don't mutate threads (archive/delete/draft) in another tab while searching.
- Exclude drafts and scheduled-send folders if you hit id-less rows.
- Retry once after a short delay before escalating.
- Update the CLI if the error is deterministic — the record layout likely shifted.
When it happens
Trigger: A /i/bv thread record where position 3 is not a thread-id string (empty, wrong type, or moved to another index) — seen after Gmail payload-format changes or with placeholder rows for in-flight sync operations.
Common situations: Gmail A/B rollouts reordering record fields, drafts/dscheduled-send placeholders mid-creation, rows for threads being deleted concurrently while the search page loads.
Related errors
- Gmail batch-view returned a malformed thread at index ${inde
- Gmail batch-view response had an unexpected shape
- Gmail returned a malformed label at index ${index}
- Gmail fetch-data response had an unexpected shape
- Gmail fetch-data returned a malformed message
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/5abe175475a888fd.
Report an issue: GitHub.