jackwener/OpenCLI · error · CommandExecutionError

Gmail batch-view response had an unexpected shape

Error message

Gmail batch-view response had an unexpected shape

What it means

parseBatchView validates that the Gmail batch-view (/i/bv) payload is an array of exactly 19 elements before extracting thread rows from body[2]. If the captured body is an array of any other length (or not an array), it throws this CommandExecutionError because the batch-view wire format it knows has changed or the wrong response was captured. It signals a structural mismatch, not bad user input.

Source

Thrown at clis/gmail/utils.js:135

  if (!Array.isArray(value)) return null;
  const address = cleanString(value[1]);
  if (!address.includes('@')) return null;
  return { address, name: cleanString(value[2]) || null };
}

function senderFromSummary(message) {
  return addressRef(Array.isArray(message) ? message[1] : null);
}

function labelIdsFromMessages(messages) {
  return [...new Set((Array.isArray(messages) ? messages : [])
    .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,

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the command; if it persists, capture the raw payload and report it — the parser needs updating for the new shape.
  2. Update opencli to the latest version so parseBatchView matches the current Gmail wire format.
  3. Verify the captured page is the normal Gmail mail view (not settings/offline), then rerun.
  4. Clear Gmail's cache/cookies and reload to rule out stale app bundles serving a different shape.
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

function isBatchViewEnvelope(body) {
  return Array.isArray(body) && body.length === 19 && Array.isArray(body[2]);
}

Try / catch

try {
  threads = await gmailSearch(query);
} catch (error) {
  if (String(error.message).includes('unexpected shape')) {
    reportToVendor('gmail batch-view payload shape changed', error);
    // fallback: narrow the query and retry once
    threads = await gmailSearch(query + ' newer_than:90d');
  } else throw error;
}

Prevention

When it happens

Trigger: waitGmailCaptures hands parseBatchView a body that is not an array or whose length !== 19 — e.g. Gmail's batch-view protocol changed, a different /sync response matched the /i/bv filter, or a partial/garbage payload was captured.

Common situations: Gmail web-app rollout changing the bv payload shape, capturing a non-list response (e.g. settings or a different sync channel) that shares the /i/bv URL, future Gmail versions.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/96c51f0cdb6e822d. Report an issue: GitHub.