jackwener/OpenCLI · error · CommandExecutionError

HTTP ${result.httpStatus} from /api/user

Error message

HTTP ${result.httpStatus} from /api/user

What it means

The in-page probe of Kimi's `/api/user` returns `{kind:'http', httpStatus}` when the fetch completes but with a non-success, non-auth HTTP status. verifyKimiIdentity surfaces that as CommandExecutionError with the status code. This signals a server-side or request-level problem rather than a plain login problem.

Source

Thrown at clis/kimi/auth.js:38

  const result = await page.evaluate(`(async () => {
    try {
      const token = ${JSON.stringify(token)};
      const res = await fetch('/api/user', { credentials: 'include', headers: { 'Authorization': 'Bearer ' + token, 'Accept': 'application/json' } });
      if (res.status === 401 || res.status === 403) {
        return { kind: 'auth', detail: 'Kimi /api/user HTTP ' + res.status };
      }
      if (!res.ok) return { kind: 'http', httpStatus: res.status };
      const d = await res.json();
      if (!d || !d.id) {
        return { kind: 'auth', detail: 'Kimi /api/user returned no id — anonymous' };
      }
      return { ok: true, user_id: String(d.id), name: String(d.name || '') };
    } catch (e) {
      return { kind: 'exception', detail: String(e && e.message || e) };
    }
  })()`);
  if (result?.kind === 'auth') throw new AuthRequiredError('kimi.com', result.detail);
  if (result?.kind === 'http') throw new CommandExecutionError(`HTTP ${result.httpStatus} from /api/user`);
  if (result?.kind === 'exception') throw new CommandExecutionError(`Kimi whoami failed: ${result.detail}`);
  if (!result?.ok) throw new CommandExecutionError(`Unexpected Kimi probe: ${JSON.stringify(result)}`);
  return { user_id: result.user_id, name: result.name };
}

registerSiteAuthCommands({
  site: 'kimi',
  domain: 'kimi.com',
  loginUrl: 'https://www.kimi.com/',
  columns: ['user_id', 'name'],
  quickCheck: hasKimiSessionCookie,
  verify: verifyKimiIdentity,
  poll: async (page) => {
    if (!await hasKimiSessionCookie(page)) {
      throw new AuthRequiredError('kimi.com', 'Waiting for Kimi auth cookies');
    }
    return verifyKimiIdentity(page);
  },

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check the reported HTTP status: retry after a delay for 429/5xx, since these are usually transient
  2. Reduce request frequency / add backoff between Kimi commands
  3. Load https://www.kimi.com in the browser to pass any bot-protection challenge, then retry
  4. If persistent, check Kimi status/changes to /api/user and update the probe

Example fix

// before
await page.evaluate(fetchProbe); // throws HTTP 429
// after
await page.wait(30); // back off before retrying
const result = await page.evaluate(fetchProbe);
Defensive patterns

Strategy: retry

Validate before calling

const res = await page.evaluate(`fetch('/api/user').then(r => r.status).catch(() => -1)`);
if (res === 429 || res >= 500) {
  await new Promise(r => setTimeout(r, 30000)); // back off before retry
}

Type guard

function isTransientHttp(status) {
  return status === 429 || (status >= 500 && status <= 599);
}

Try / catch

try {
  await kimiWhoami();
} catch (e) {
  const m = e.message.match(/HTTP (\d+) from \/api\/user/);
  if (m && (m[1] === '429' || +m[1] >= 500)) {
    await sleep(30000);
    return kimiWhoami();
  }
  throw e;
}

Prevention

When it happens

Trigger: `/api/user` responds with an unexpected HTTP status (e.g. 429 rate limit, 500 server error, 403 from a WAF/bot protection) that the probe classifies as 'http' rather than 'auth'.

Common situations: Hammering Kimi's API in a loop and hitting rate limiting; Kimi outage or maintenance returning 5xx; Cloudflare/bot-protection challenging automated requests; regional blocking of the API endpoint.

Related errors


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