{"record":{"id":"b9d41ed1f47061dd","repo":"jackwener/OpenCLI","slug":"gmail-fetch-data-returned-a-malformed-message","errorCode":null,"errorMessage":"Gmail fetch-data returned a malformed message","messagePattern":"Gmail fetch-data returned a malformed message","errorType":"error_code","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/gmail/utils.js","lineNumber":253,"sourceCode":"      size: Number.isFinite(Number(data[4])) ? Number(data[4]) : null,\n    });\n  }\n  return out;\n}\n\nexport function parseFetchData(body) {\n  if (!Array.isArray(body) || !Array.isArray(body[1])) {\n    throw new CommandExecutionError('Gmail fetch-data response had an unexpected shape');\n  }\n  const messages = [];\n  for (const threadWrapper of body[1]) {\n    const threadId = cleanString(threadWrapper?.[0]).replace(/^#/, '');\n    const rows = Array.isArray(threadWrapper?.[2]) ? threadWrapper[2] : [];\n    for (const wrapper of rows) {\n      const messageId = cleanString(wrapper?.[0]).replace(/^#/, '');\n      const record = Array.isArray(wrapper?.[1]) ? wrapper[1] : null;\n      if (!threadId || !messageId || !record) {\n        throw new CommandExecutionError('Gmail fetch-data returned a malformed message');\n      }\n      const from = senderFromRecord(record);\n      const attachments = parseAttachments(record);\n      messages.push({\n        messageId,\n        legacyMessageId: cleanString(record[34]) || null,\n        threadId,\n        subject: cleanString(record[4]) || '(no subject)',\n        from: from?.address || null,\n        fromName: from?.name || null,\n        to: addressList(record[0]).map((item) => item.address).join(', ') || null,\n        cc: addressList(record[1]).map((item) => item.address).join(', ') || null,\n        date: gmailDate(record[16], `message ${messageId}`),\n        snippet: cleanString(record[6]) || null,\n        body: messageBody(record) || null,\n        attachments,\n      });\n    }","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/gmail/utils.js#L235-L271","documentation":"Inside parseFetchData, each message wrapper must yield a non-empty threadId (wrapper[0]), a non-empty messageId (wrapper[0] of the row), and a record array at wrapper[1]. If any of these is missing this CommandExecutionError is thrown. Without these keys the message cannot be addressed or rendered, so the library refuses the whole payload rather than returning partial data.","triggerScenarios":"A /i/fd response containing a row whose message id is empty, whose record array is absent, or whose enclosing thread wrapper lacks a thread id — placeholder rows while the thread is streaming in, or a Gmail field-layout change.","commonSituations":"Opening a thread while Gmail is still hydrating it, messages being deleted/expunged concurrently, Gmail A/B rollouts changing per-message record positions, very large threads partially synced.","solutions":["Retry after letting the thread fully render in the browser — mid-load captures cause empty ids.","Update opencli if Gmail moved message record fields.","Reload Gmail and reopen the thread, then rerun the command.","Fetch the thread again excluding it from bulk operations if it is being modified concurrently."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"null","typeGuard":"function isMessageWrapper(row) {\n  const id = typeof row?.[0] === 'string' ? row[0].replace(/^#/, '').trim() : '';\n  return id.length > 0 && Array.isArray(row?.[1]);\n}","tryCatchPattern":"try {\n  messages = await gmailThread(threadId);\n} catch (error) {\n  if (String(error.message).includes('malformed message')) {\n    await sleep(2000); // allow Gmail to finish hydrating the thread\n    messages = await gmailThread(threadId);\n  } else throw error;\n}","preventionTips":["Wait for the thread to fully render in the browser before fetching programmatically.","Avoid fetching threads that are being modified (deletion, send, label changes) concurrently.","Retry with a short backoff — mid-hydration captures are the dominant cause.","Update the CLI if failures are deterministic; the per-message record layout may have changed."],"tags":["gmail","fetch-data","malformed-message","schema-validation"],"backgroundTag":"unexpected-response-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}