jackwener/OpenCLI · warning · EmptyResultError

gmail labels

gmail labels

Error message

Gmail returned no labels

What it means

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.

Source

Thrown at clis/gmail/utils.js:555

      throw new CommandExecutionError(`Gmail thread pagination page ${pageNumber} repeated an earlier response; refusing partial results`);
    }
    if (pageRows.length < PAGE_SIZE) break;
  }
  if (rows.length === 0) {
    throw new EmptyResultError('gmail search', `No threads matched "${normalizedQuery}"`);
  }
  return rows.slice(0, limit);
}

export async function listLabels(page, account = 0) {
  await ensureGmailReady(page, account, 'labels');
  await installGmailCapture(page, account, 'bv', 'labels');
  await submitSearch(page, 'in:anywhere', 'labels');
  const bodies = await waitGmailCaptures(page, 'bv', 'labels');
  const labels = bodies.flatMap(parseLabels);
  const fallback = labels.length === 0 ? await renderedLabels(page, account) : [];
  const unique = [...new Map([...labels, ...fallback].map((row) => [row.id, row])).values()];
  if (unique.length === 0) throw new EmptyResultError('gmail labels', 'Gmail returned no labels');
  return unique;
}

export function legacyThreadId(value) {
  const raw = cleanString(value);
  const fromUrl = raw.match(/\/(?:[a-f\d]{10,})$/i)?.[0]?.slice(1);
  if (fromUrl) return fromUrl.toLowerCase();
  if (/^[a-f\d]{10,}$/i.test(raw)) return raw.toLowerCase();
  const sync = raw.replace(/^#/, '').match(/^thread-f:(\d+)$/);
  if (sync) return BigInt(sync[1]).toString(16);
  throw new ArgumentError('thread must be a Gmail thread id from `gmail search` or a Gmail thread URL');
}

export async function fetchThread(page, target, account = 0) {
  const legacyId = legacyThreadId(target);
  await ensureGmailReady(page, account, 'thread');
  await installGmailCapture(page, account, 'fd', 'thread');
  const targetState = unwrapBrowserResult(await page.evaluate(`async () => {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry after ensuring Gmail is fully loaded (increase wait/retry)
  2. Navigate to a mailbox view first so the labels UI renders
  3. Update the library if Google changed the Gmail DOM
  4. Verify the account is fully set up and logged in

Example fix

// before
const labels = await listLabels(page);
// after
await ensureGmailReady(page, 0, 'labels'); // or explicit pre-navigation
const labels = await listLabels(page);
if (labels.length === 0) console.warn('no labels found — UI may have changed');
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try { labels = await listLabels(page); }
catch (e) { if (e instanceof EmptyResultError) { labels = []; await page.sleep(2); labels = await listLabels(page).catch(() => []); } else throw e; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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