jackwener/OpenCLI · critical · AuthRequiredError

Gmail ${operation} returned HTTP ${status}

Error message

Gmail ${operation} returned HTTP ${status}

What it means

parseJsonCapture inspects a browser network capture of a Gmail API request. HTTP 401/403 means Gmail rejected the request for auth/permission reasons, so the library throws AuthRequiredError for the Gmail host instead of a generic execution error — the session is logged out or lacks access.

Source

Thrown at clis/gmail/utils.js:94

}

export function htmlToText(value) {
  return decodeEntities(String(value || '')
    .replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, ' ')
    .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, ' ')
    .replace(/<br\s*\/?\s*>/gi, '\n')
    .replace(/<\/(p|div|li|tr|h[1-6])>/gi, '\n')
    .replace(/<[^>]+>/g, ' '))
    .replace(/[ \t]+/g, ' ')
    .replace(/ *\n */g, '\n')
    .replace(/\n{3,}/g, '\n\n')
    .trim();
}

function parseJsonCapture(entry, operation) {
  const status = Number(entry?.responseStatus || 0);
  if (status === 401 || status === 403) {
    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`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate in the browser: open the Gmail profile at /mail/u/<index>/ and log in again.
  2. Verify the correct account index is being used (an unauthenticated profile returns 401/403).
  3. Check for Google security blocks (unusual activity prompts) and clear them in the browser.
  4. If on a managed workspace account, confirm with the admin that automated access isn't blocked by policy.

Example fix

// before
cli gmail search --query x  // capture shows HTTP 401
// after
browser open https://mail.google.com/mail/u/0/  // log in again
cli gmail search --query x
Defensive patterns

Strategy: try-catch

Validate before calling

// Can't pre-check server-side auth, but verify the browser is signed in first:
const signedIn = await page.evaluate(() =>
  !document.querySelector('a[href*="accounts.google.com/SignOutOptions"], form[action*="ServiceLogin"]') === false
    ? 'unknown' : 'signed-in');

Try / catch

try {
  await waitGmailCaptures(captures, 'search');
} catch (e) {
  if (e instanceof AuthRequiredError) {
    await openGmailAndLogin(accountIndex); // re-authenticate
    return waitGmailCaptures(captures, 'search');
  }
  throw e;
}

Prevention

When it happens

Trigger: The captured request for `operation` returned status 401 (session cookie expired / logged out) or 403 (account access denied, suspicious-activity block, or workspace policy) while polling captures via waitGmailCaptures.

Common situations: Google sessions expiring after days/weeks of browser uptime; Google signing the profile out due to security changes; restricted/workspace accounts where the automation is denied; using an account index where the user isn't signed in.

Related errors


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