{"record":{"id":"26eb3f6d26f78d47","repo":"jackwener/OpenCLI","slug":"gmail-labels","errorCode":"gmail labels","errorMessage":"Gmail returned no labels","messagePattern":"Gmail returned no labels","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/gmail/utils.js","lineNumber":555,"sourceCode":"      throw new CommandExecutionError(`Gmail thread pagination page ${pageNumber} repeated an earlier response; refusing partial results`);\n    }\n    if (pageRows.length < PAGE_SIZE) break;\n  }\n  if (rows.length === 0) {\n    throw new EmptyResultError('gmail search', `No threads matched \"${normalizedQuery}\"`);\n  }\n  return rows.slice(0, limit);\n}\n\nexport async function listLabels(page, account = 0) {\n  await ensureGmailReady(page, account, 'labels');\n  await installGmailCapture(page, account, 'bv', 'labels');\n  await submitSearch(page, 'in:anywhere', 'labels');\n  const bodies = await waitGmailCaptures(page, 'bv', 'labels');\n  const labels = bodies.flatMap(parseLabels);\n  const fallback = labels.length === 0 ? await renderedLabels(page, account) : [];\n  const unique = [...new Map([...labels, ...fallback].map((row) => [row.id, row])).values()];\n  if (unique.length === 0) throw new EmptyResultError('gmail labels', 'Gmail returned no labels');\n  return unique;\n}\n\nexport function legacyThreadId(value) {\n  const raw = cleanString(value);\n  const fromUrl = raw.match(/\\/(?:[a-f\\d]{10,})$/i)?.[0]?.slice(1);\n  if (fromUrl) return fromUrl.toLowerCase();\n  if (/^[a-f\\d]{10,}$/i.test(raw)) return raw.toLowerCase();\n  const sync = raw.replace(/^#/, '').match(/^thread-f:(\\d+)$/);\n  if (sync) return BigInt(sync[1]).toString(16);\n  throw new ArgumentError('thread must be a Gmail thread id from `gmail search` or a Gmail thread URL');\n}\n\nexport async function fetchThread(page, target, account = 0) {\n  const legacyId = legacyThreadId(target);\n  await ensureGmailReady(page, account, 'thread');\n  await installGmailCapture(page, account, 'fd', 'thread');\n  const targetState = unwrapBrowserResult(await page.evaluate(`async () => {","sourceCodeStart":537,"sourceCodeEnd":573,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/gmail/utils.js#L537-L573","documentation":"listLabels() collects labels from Gmail's DOM captures, falls back to a rendered-labels scrape, dedupes, and throws EmptyResultError ('gmail labels') if nothing was found. It indicates Gmail loaded but produced no label data the library could parse.","triggerScenarios":"listLabels(page, account) when both the capture-based parse and the renderedLabels fallback return nothing — e.g. Gmail not fully loaded, a Gmail UI change breaking parsers, or an account/page state with no labels in view.","commonSituations":"Automating a fresh account where the page redirects to a welcome/empty state; Google changing the Gmail DOM; slow load where the wait for captures times out to zero results.","solutions":["Retry after ensuring Gmail is fully loaded (increase wait/retry)","Navigate to a mailbox view first so the labels UI renders","Update the library if Google changed the Gmail DOM","Verify the account is fully set up and logged in"],"exampleFix":"// before\nconst labels = await listLabels(page);\n// after\nawait ensureGmailReady(page, 0, 'labels'); // or explicit pre-navigation\nconst labels = await listLabels(page);\nif (labels.length === 0) console.warn('no labels found — UI may have changed');","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try { labels = await listLabels(page); }\ncatch (e) { if (e instanceof EmptyResultError) { labels = []; await page.sleep(2); labels = await listLabels(page).catch(() => []); } else throw e; }","preventionTips":["Ensure Gmail is fully loaded/logged in before listing labels","Retry once on empty label results","Watch for Gmail DOM changes requiring a library update"],"tags":["empty-result","gmail","labels"],"backgroundTag":"empty-search-results","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}