JuliusBrussee/caveman · error · Error

device authorization failed: HTTP ${codeResponse.status}

Error message

device authorization failed: HTTP ${codeResponse.status}

What it means

runCavemanDeviceFlow POSTs to /api/v1/auth/device/code with a 5-second timeout to start the device authorization grant. A non-2xx response (bad gateway, auth server error, rate limit, wrong path) aborts immediately with the HTTP status embedded in this error.

Source

Thrown at packages/device-auth/src/index.ts:102

export async function runCavemanDeviceFlow(options: {
  baseURL: string;
  client: string;
  fetch?: typeof globalThis.fetch;
  signal?: AbortSignal;
  sleep?: (ms: number) => Promise<void>;
  onCode?: (code: DeviceCode) => void | Promise<void>;
}): Promise<DeviceGrant> {
  const fetcher = options.fetch ?? globalThis.fetch;
  const wait = options.sleep ?? defaultSleep;
  const baseURL = options.baseURL.replace(/\/$/, "");
  const codeResponse = await fetcher(`${baseURL}/api/v1/auth/device/code`, {
    method: "POST",
    headers: { "content-type": "application/json", "x-cave-client": options.client },
    body: "{}",
    signal: requestSignal(options.signal, 5000),
  });
  if (!codeResponse.ok) throw new Error(`device authorization failed: HTTP ${codeResponse.status}`);
  const rawCode = await codeResponse.json().catch(() => null) as Partial<DeviceCode> | null;
  if (rawCode === null || typeof rawCode.device_code !== "string" || rawCode.device_code === "" ||
    typeof rawCode.user_code !== "string" || typeof rawCode.verification_uri !== "string" ||
    typeof rawCode.expires_in !== "number" || !Number.isFinite(rawCode.expires_in) || rawCode.expires_in <= 0) {
    throw new Error(`device authorization failed: ${JSON.stringify(rawCode)}`);
  }
  const code = rawCode as DeviceCode;
  await options.onCode?.(structuredClone(code));
  let intervalMs = Math.max(0, Number(code.interval ?? 5)) * 1000;
  const deadline = Date.now() + code.expires_in * 1000;
  while (Date.now() < deadline) {
    let payload: Record<string, unknown>;
    let status = 0;
    let retryAfterMs = 0;
    try {
      const response = await fetcher(`${baseURL}/api/v1/auth/device/token`, {
        method: "POST",
        headers: { "content-type": "application/json", "x-cave-client": options.client },

View on GitHub (pinned to df2ccd85c9)

Solutions

  1. Print/verify the status in the message and hit the endpoint manually: `curl -i -X POST ${baseURL}/api/v1/auth/device/code` to see the real error.
  2. Fix baseURL to the correct environment/API version.
  3. If 429, wait and retry with backoff.
  4. Check proxy/firewall rules if an intermediary (403/502/503) is generating the status.
  5. Retry during a confirmed server outage; check the provider's status page.

Example fix

// before
await runCavemanDeviceFlow({ baseURL: "https://api.example.com/v2", ... }); // v2 has no /auth/device/code
// after
await runCavemanDeviceFlow({ baseURL: "https://api.example.com/v1", ... }); // correct API version
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(`${baseURL}/api/v1/auth/device/code`, { method: "HEAD" }).catch(() => null);
if (!res || !res.ok) throw new Error(`device code endpoint not healthy (baseURL=${baseURL})`);

Try / catch

try {
  await runCavemanDeviceFlow(options);
} catch (e) {
  if (e instanceof Error && /device authorization failed: HTTP (429|5\d\d)/.test(e.message)) {
    await sleep(10000);           // transient server/rate-limit issue
    await runCavemanDeviceFlow(options);
  } else throw e;
}

Prevention

When it happens

Trigger: The POST /api/v1/auth/device/code request returns any !ok status — e.g. 404 (wrong baseURL/path), 500 (server error), 429 (rate limited), 502/503 (gateway down).

Common situations: baseURL pointing to a stale or wrong environment after an API version change; auth service outage; corporate proxy returning 403/502 for the endpoint; aggressive client causing 429s.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@df2ccd85c9 (2026-08-31). Data as JSON: /api/errors/06229a6bb58b97df. Report an issue: GitHub.