jackwener/OpenCLI · error · CommandExecutionError

Gmail thread navigation failed

Error message

Gmail thread navigation failed

What it means

fetchThread() navigates via a hash change to '#all/<legacyId>' inside page.evaluate; if the wrapper (unwrapBrowserResult) returns anything other than true, the library throws CommandExecutionError 'Gmail thread navigation failed'. It signals the in-page navigation script did not complete as expected.

Source

Thrown at clis/gmail/utils.js:592

    const row = document.querySelector('[data-legacy-thread-id="${legacyId}"]');
    if (!row) return { found: false };
    const clickable = row.querySelector('.y6, .bog, td:nth-child(5)') || row;
    const before = location.href;
    clickable.click();
    await new Promise((resolve) => setTimeout(resolve, 150));
    const rect = clickable.getBoundingClientRect();
    return { found: true, changed: location.href !== before, x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
  }`), 'thread row lookup');
  if (targetState?.found && !targetState.changed && typeof page.nativeClick === 'function') {
    await page.nativeClick(targetState.x, targetState.y);
  } else if (!targetState?.found) {
    const navigated = unwrapBrowserResult(await page.evaluate(`() => {
    const target = ${JSON.stringify(`#all/${legacyId}`)};
    if (window.location.hash === target) window.location.hash = '#inbox';
    setTimeout(() => { window.location.hash = target; }, 50);
    return true;
  }`), 'thread navigation');
    if (navigated !== true) throw new CommandExecutionError('Gmail thread navigation failed');
  }
  let messages = [];
  try {
    const bodies = await waitGmailCaptures(page, 'fd', 'thread', 3);
    messages = bodies.flatMap(parseFetchData);
  } catch (error) {
    if (!(error instanceof TimeoutError)) throw error;
    await page.sleep(0.5);
    messages = await renderedThread(page, target);
    if (messages.length === 0) throw error;
  }
  const unique = [...new Map(messages.map((message) => [message.messageId, message])).values()];
  if (unique.length === 0) {
    throw new EmptyResultError('gmail thread', `No messages found for thread ${target}`);
  }
  return unique;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate / ensure the Gmail session is logged in, then retry
  2. Retry the fetch once — transient races resolve on a second attempt
  3. Verify the page is on Gmail (correct account, not a login or error page)
  4. Check browser console for script errors blocking the evaluate

Example fix

// before
const thread = await fetchThread(page, threadId); // one-shot
// after
let thread;
try { thread = await fetchThread(page, threadId); }
catch (e) {
  if (e instanceof CommandExecutionError) { await page.reload(); thread = await fetchThread(page, threadId); }
  else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

const hash = await page.evaluate('() => window.location.hash');
if (!hash || !hash.includes('mail.google.com') === false) /* on Gmail */;

Type guard

null

Try / catch

try { thread = await fetchThread(page, id); }
catch (e) { if (e instanceof CommandExecutionError && e.message === 'Gmail thread navigation failed') { await page.reload(); thread = await fetchThread(page, id); } else throw e; }

Prevention

When it happens

Trigger: The evaluate call fails or returns a wrapped error result; the browser context is unresponsive or the page navigated away mid-call; Gmail rejected the hash change (invalid id or blocked navigation).

Common situations: Stale/expired Gmail session where navigation is redirected to login; browser tab closed or crashed; extension or CSP interfering with hash navigation; a race where the page reloads during evaluate.

Related errors


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