{"record":{"id":"5abe175475a888fd","repo":"jackwener/OpenCLI","slug":"gmail-batch-view-returned-a-thread-without-an-id-a","errorCode":null,"errorMessage":"Gmail batch-view returned a thread without an id at index ${index}","messagePattern":"Gmail batch-view returned a thread without an id at index (.+?)","errorType":"error_code","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/gmail/utils.js","lineNumber":147,"sourceCode":"    .flatMap((message) => Array.isArray(message?.[10]) ? message[10] : [])\n    .filter((label) => typeof label === 'string' && label.startsWith('^')))];\n}\n\nexport function parseBatchView(body) {\n  if (!Array.isArray(body) || body.length !== 19) {\n    throw new CommandExecutionError('Gmail batch-view response had an unexpected shape');\n  }\n  const rows = Array.isArray(body[2]) ? body[2] : [];\n  return rows.map((wrapper, index) => {\n    const record = Array.isArray(wrapper?.[0]) ? wrapper[0] : null;\n    if (!record || record.length < 5) {\n      throw new CommandExecutionError(`Gmail batch-view returned a malformed thread at index ${index}`);\n    }\n    const threadId = cleanString(record[3]).replace(/^#/, '');\n    const messages = Array.isArray(record[4]) ? record[4] : [];\n    const latest = messages.at(-1);\n    const sender = senderFromSummary(latest);\n    if (!threadId) throw new CommandExecutionError(`Gmail batch-view returned a thread without an id at index ${index}`);\n    const labels = labelIdsFromMessages(messages);\n    return {\n      threadId,\n      subject: cleanString(record[0]) || '(no subject)',\n      from: sender?.address || null,\n      fromName: sender?.name || null,\n      snippet: cleanString(record[1]) || null,\n      messageCount: messages.length,\n      unread: labels.includes('^u'),\n      starred: labels.includes('^t'),\n      date: gmailDate(record[2], `thread ${threadId}`),\n      labels,\n    };\n  });\n}\n\nfunction labelCounts(value) {\n  const result = new Map();","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/gmail/utils.js#L129-L165","documentation":"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.","triggerScenarios":"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.","commonSituations":"Gmail A/B rollouts reordering record fields, drafts/dscheduled-send placeholders mid-creation, rows for threads being deleted concurrently while the search page loads.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"null","typeGuard":"function hasThreadId(record) {\n  return typeof record?.[3] === 'string' && record[3].trim().length > 0;\n}","tryCatchPattern":"try {\n  threads = await gmailSearch(query);\n} catch (error) {\n  if (String(error.message).includes('thread without an id')) {\n    await sleep(1500); // let in-flight sync placeholders resolve\n    threads = await gmailSearch(query);\n  } else throw error;\n}","preventionTips":["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."],"tags":["gmail","batch-view","missing-thread-id","schema-validation"],"backgroundTag":"unexpected-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}