jackwener/OpenCLI · error · CommandExecutionError

HTTP ${result.httpStatus} from /voyager/api/me

Error message

HTTP ${result.httpStatus} from /voyager/api/me

What it means

The whoami probe to /voyager/api/me answered with a non-success HTTP status (kind:'http'); the library throws CommandExecutionError embedding that status. Typically a 401/403 (bad session or CSRF token) but any failing status is surfaced verbatim.

Source

Thrown at clis/linkedin/auth.js:43

      const d = await res.json();
      const mini = d && d.miniProfile;
      if (!mini || !mini.publicIdentifier) {
        return { kind: 'auth', detail: 'LinkedIn /voyager/api/me 200 but miniProfile missing' };
      }
      const firstName = (mini.firstName && (mini.firstName.text || mini.firstName)) || '';
      const lastName = (mini.lastName && (mini.lastName.text || mini.lastName)) || '';
      return {
        ok: true,
        public_id: String(mini.publicIdentifier),
        plain_id: String(d.plainId || ''),
        name: String((firstName + ' ' + lastName).trim()),
      };
    } catch (e) {
      return { kind: 'exception', detail: String(e && e.message || e) };
    }
  })()`);
  if (result?.kind === 'auth') throw new AuthRequiredError('linkedin.com', result.detail);
  if (result?.kind === 'http') throw new CommandExecutionError(`HTTP ${result.httpStatus} from /voyager/api/me`);
  if (result?.kind === 'exception') throw new CommandExecutionError(`LinkedIn whoami failed: ${result.detail}`);
  if (!result?.ok) throw new CommandExecutionError(`Unexpected LinkedIn probe: ${JSON.stringify(result)}`);
  return { public_id: result.public_id, plain_id: result.plain_id, name: result.name };
}

registerSiteAuthCommands({
  site: 'linkedin',
  domain: 'www.linkedin.com',
  loginUrl: 'https://www.linkedin.com/login',
  columns: ['public_id', 'plain_id', 'name'],
  quickCheck: hasLinkedinSessionCookie,
  verify: verifyLinkedinIdentity,
  poll: async (page) => {
    if (!await hasLinkedinSessionCookie(page)) {
      throw new AuthRequiredError('linkedin.com', 'Waiting for LinkedIn li_at cookie');
    }
    return verifyLinkedinIdentity(page);
  },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Re-authenticate (fresh login) if the status is 401/403.
  2. Add backoff/spacing between LinkedIn calls to avoid 429 throttling.
  3. Retry on 5xx after a short delay — often transient.
  4. Verify the JSESSIONID cookie is being sent with the request; a bad CSRF token yields 403.

Example fix

// before
await run('linkedin whoami'); // CommandExecutionError: HTTP 403 from /voyager/api/me
// after
await sleep(60000);            // cool down after throttling
await run('auth linkedin');    // refresh session if 401/403 persists
await run('linkedin whoami');
Defensive patterns

Strategy: retry

Validate before calling

null

Type guard

null

Try / catch

async function whoamiWithRetry() {
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      return await run('linkedin whoami');
    } catch (e) {
      const m = /HTTP (\d{3}) from \/voyager\/api\/me/.exec(e.message);
      if (!m) throw e;
      const status = Number(m[1]);
      if (status === 401 || status === 403) { await run('auth linkedin'); continue; }
      if (status >= 500 || status === 429) { await sleep(30000 * (attempt + 1)); continue; }
      throw e;
    }
  }
  throw new Error('whoami failed after retries');
}

Prevention

When it happens

Trigger: page.evaluate probe's fetch to /voyager/api/me returns httpStatus other than ok — e.g. 401 after session expiry, 403 rate-limit/bot-detection, 5xx from LinkedIn.

Common situations: Rapid automated requests triggering LinkedIn rate limits; missing JSESSIONID header paired with li_at causing 401; LinkedIn Voyager API rejecting stale CSRF tokens; transient LinkedIn 5xx.

Related errors


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