jackwener/OpenCLI · error · CommandExecutionError

Claude whoami failed

Error message

Claude whoami failed: ${result.detail}

What it means

This CommandExecutionError wraps any JavaScript exception thrown inside the in-page fetch probe to /api/organizations (the caught error is stringified into result.detail). It indicates the whoami verification script itself crashed in the browser context rather than receiving a normal HTTP response — e.g. a failed fetch (network/DNS error), JSON parsing failure, or a Claude page change that breaks the script.

Solutions

  1. Read result.detail in the message to see the underlying exception and address it specifically
  2. Verify general internet connectivity and that https://claude.ai loads in the browser without a Cloudflare challenge
  3. Disable conflicting extensions (ad-blockers/script blockers) or bypass VPN/proxy, then retry
  4. Re-run the login flow (`opencli claude auth`) so the probe runs on a freshly loaded claude.ai page
  5. Update the library — Claude may have changed its response format and a newer probe handles it

Example fix

// before
const res = await fetch('/api/organizations', { credentials: 'include' }); // TypeError: Failed to fetch (offline)
// after
// ensure connectivity first, then retry:
ping claude.ai && opencli claude whoami
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure connectivity before running browser probes
const res = await fetch('https://claude.ai/robots.txt').catch(() => null);
if (!res || !res.ok) throw new Error('claude.ai unreachable — check network/VPN/proxy');

Type guard

function isProbeException(result) {
  return !!result && result.kind === 'exception' && typeof result.detail === 'string';
}

Try / catch

try {
  const identity = await verifyClaudeIdentity(page);
} catch (e) {
  if (e.message.startsWith('Claude whoami failed:')) {
    console.error('Probe crashed in page:', e.message);
    // check network, disable interfering extensions, reload page and retry once
  }
  throw e;
}

Prevention

When it happens

Trigger: The page.evaluate probe's try block throws: network failure reaching /api/organizations (offline, DNS failure, proxy block), res.json() failing on a non-JSON response (login redirect HTML, Cloudflare challenge page), or an injected script/CSP change breaking evaluation.

Common situations: Corporate proxy or VPN blocking claude.ai API calls; Cloudflare interstitial returning HTML so JSON parsing throws; internet drop mid-probe; browser extension or CSP changes blocking in-page fetch; Claude frontend returning an unexpected payload shape after an update.

Related errors


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

Appendix: source

Thrown at clis/claude/auth.js:36

      if (res.status === 401 || res.status === 403) {
        return { kind: 'auth', detail: 'Claude /api/organizations HTTP ' + res.status };
      }
      if (!res.ok) return { kind: 'http', httpStatus: res.status };
      const d = await res.json();
      if (!Array.isArray(d) || d.length === 0) {
        return { kind: 'auth', detail: 'Claude /api/organizations empty' };
      }
      const userIdCookie = (document.cookie.split('; ').find(c => c.startsWith('ajs_user_id=')) || '').split('=')[1] || '';
      const activeOrgCookie = (document.cookie.split('; ').find(c => c.startsWith('lastActiveOrg=')) || '').split('=')[1] || '';
      const activeOrg = d.find(o => o.uuid === activeOrgCookie) || d[0];
      return { ok: true, user_id: userIdCookie, org_name: activeOrg.name || '', org_uuid: activeOrg.uuid || '' };
    } catch (e) {
      return { kind: 'exception', detail: String(e && e.message || e) };
    }
  })()`);
  if (result?.kind === 'auth') throw new AuthRequiredError('claude.ai', result.detail);
  if (result?.kind === 'http') throw new CommandExecutionError(`HTTP ${result.httpStatus} from /api/organizations`);
  if (result?.kind === 'exception') throw new CommandExecutionError(`Claude whoami failed: ${result.detail}`);
  if (!result?.ok) throw new CommandExecutionError(`Unexpected Claude probe: ${JSON.stringify(result)}`);
  if (!result.user_id) throw new AuthRequiredError('claude.ai', 'Claude session incomplete — ajs_user_id cookie missing');
  return { user_id: String(result.user_id), org_name: String(result.org_name), org_uuid: String(result.org_uuid) };
}

registerSiteAuthCommands({
  site: 'claude',
  domain: 'claude.ai',
  loginUrl: 'https://claude.ai/login',
  columns: ['user_id', 'org_name', 'org_uuid'],
  quickCheck: hasClaudeSessionCookie,
  verify: verifyClaudeIdentity,
  poll: async (page) => {
    if (!await hasClaudeSessionCookie(page)) {
      throw new AuthRequiredError('claude.ai', 'Waiting for Claude sessionKey cookie');
    }
    return verifyClaudeIdentity(page);
  },

View on GitHub (pinned to 49907e53dc)