{"record":{"id":"7618e554227dd973","repo":"jackwener/OpenCLI","slug":"gmail-operation-returned-http-status","errorCode":null,"errorMessage":"Gmail ${operation} returned HTTP ${status}","messagePattern":"Gmail (.+?) returned HTTP (.+?)","errorType":"error_code","errorClass":"AuthRequiredError","httpStatus":401,"severity":"critical","filePath":"clis/gmail/utils.js","lineNumber":94,"sourceCode":"}\n\nexport function htmlToText(value) {\n  return decodeEntities(String(value || '')\n    .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, ' ')\n    .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, ' ')\n    .replace(/<br\\s*\\/?\\s*>/gi, '\\n')\n    .replace(/<\\/(p|div|li|tr|h[1-6])>/gi, '\\n')\n    .replace(/<[^>]+>/g, ' '))\n    .replace(/[ \\t]+/g, ' ')\n    .replace(/ *\\n */g, '\\n')\n    .replace(/\\n{3,}/g, '\\n\\n')\n    .trim();\n}\n\nfunction parseJsonCapture(entry, operation) {\n  const status = Number(entry?.responseStatus || 0);\n  if (status === 401 || status === 403) {\n    throw new AuthRequiredError(GMAIL_HOST, `Gmail ${operation} returned HTTP ${status}`);\n  }\n  if (status !== 200) {\n    throw new CommandExecutionError(`Gmail ${operation} returned HTTP ${status || 'unknown'}`);\n  }\n  if (entry?.responseBodyTruncated === true) {\n    throw new CommandExecutionError(`Gmail ${operation} response exceeded the browser capture limit`);\n  }\n  const body = entry?.responsePreview;\n  if (Array.isArray(body)) return body;\n  if (typeof body !== 'string') {\n    throw new CommandExecutionError(`Gmail ${operation} response body was unavailable`);\n  }\n  try {\n    const parsed = JSON.parse(body.replace(/^\\)\\]\\}'\\s*/, ''));\n    if (!Array.isArray(parsed)) throw new Error('not an array');\n    return parsed;\n  } catch {\n    throw new CommandExecutionError(`Gmail ${operation} returned malformed JSON`);","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/gmail/utils.js#L76-L112","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-authenticate in the browser: open the Gmail profile at /mail/u/<index>/ and log in again.","Verify the correct account index is being used (an unauthenticated profile returns 401/403).","Check for Google security blocks (unusual activity prompts) and clear them in the browser.","If on a managed workspace account, confirm with the admin that automated access isn't blocked by policy."],"exampleFix":"// before\ncli gmail search --query x  // capture shows HTTP 401\n// after\nbrowser open https://mail.google.com/mail/u/0/  // log in again\ncli gmail search --query x","handlingStrategy":"try-catch","validationCode":"// Can't pre-check server-side auth, but verify the browser is signed in first:\nconst signedIn = await page.evaluate(() =>\n  !document.querySelector('a[href*=\"accounts.google.com/SignOutOptions\"], form[action*=\"ServiceLogin\"]') === false\n    ? 'unknown' : 'signed-in');","typeGuard":null,"tryCatchPattern":"try {\n  await waitGmailCaptures(captures, 'search');\n} catch (e) {\n  if (e instanceof AuthRequiredError) {\n    await openGmailAndLogin(accountIndex); // re-authenticate\n    return waitGmailCaptures(captures, 'search');\n  }\n  throw e;\n}","preventionTips":["Periodically verify the Gmail session is still logged in before long automations.","Keep browser profiles persistent so cookies survive restarts.","Watch for Google security/signout prompts and resolve them.","Match the --account index to a profile that is actually signed in."],"tags":["auth","http-401","http-403","gmail"],"backgroundTag":"auth-required","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}