jackwener/OpenCLI · error · CommandExecutionError

Gmail ${operation} returned malformed JSON

Error message

Gmail ${operation} returned malformed JSON

What it means

This CommandExecutionError is thrown by parseJsonCapture when JSON.parse of the captured Gmail /sync body fails, or the parsed payload is not an array. Gmail prefixes its /sync JSON with the XSSI guard ')\]\}\'' which is stripped first; any remaining non-JSON content (HTML login/error page, partial body, protocol change) makes parsing fail. The library treats an unparseable capture as a failed command.

Source

Thrown at clis/gmail/utils.js:112

    throw new AuthRequiredError(GMAIL_HOST, `Gmail ${operation} returned HTTP ${status}`);
  }
  if (status !== 200) {
    throw new CommandExecutionError(`Gmail ${operation} returned HTTP ${status || 'unknown'}`);
  }
  if (entry?.responseBodyTruncated === true) {
    throw new CommandExecutionError(`Gmail ${operation} response exceeded the browser capture limit`);
  }
  const body = entry?.responsePreview;
  if (Array.isArray(body)) return body;
  if (typeof body !== 'string') {
    throw new CommandExecutionError(`Gmail ${operation} response body was unavailable`);
  }
  try {
    const parsed = JSON.parse(body.replace(/^\)\]\}'\s*/, ''));
    if (!Array.isArray(parsed)) throw new Error('not an array');
    return parsed;
  } catch {
    throw new CommandExecutionError(`Gmail ${operation} returned malformed JSON`);
  }
}

function addressRef(value) {
  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('^')))];

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Reload Gmail in the browser and confirm the mailbox is fully signed in, then rerun the command.
  2. Retry — an intermittent partial body can parse-fail once and succeed on retry.
  3. Check whether the Gmail web UI itself works in the captured browser profile; update opencli if Gmail changed its payload format.
  4. Disable interfering proxies/extensions that could rewrite the /sync response.

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the session is really signed in before automating
const html = await page.evaluate("() => document.body.innerText.slice(0, 500)");
if (/sign in|choose an account|loggen Sie sich/i.test(html)) {
  throw new Error('Gmail session is logged out; complete sign-in first');
}

Type guard

function isGmailArrayPayload(body) {
  return Array.isArray(body);
}

Try / catch

try {
  result = await gmailSearch(query);
} catch (error) {
  if (String(error.message).includes('malformed JSON')) {
    // Gmail served non-JSON (login page, error page, protocol change)
    await page.reload(); // re-establish a clean session, then retry once
    result = await gmailSearch(query);
  } else throw error;
}

Prevention

When it happens

Trigger: The /i/bv or /i/fd response body is not an array of JSON (Gmail served an HTML interstitial/sign-in page, an error payload, or a new protocol shape), or the body was cut in a way that broke JSON but was not flagged truncated.

Common situations: Gmail session half-logged-out serving redirect HTML, Gmail UI A/B rollout changing the /sync payload shape, proxy/captive portal injecting content, region-redirect pages.

Understand the failure class

Related errors


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