coleam00/Archon · error · DeviceFlowError

${result.code}

Error message

${result.code}

What it means

When a single poll returns a terminal status other than 'pending' or 'slow_down' (e.g. authorization_pending expired, access_denied, bad_verification_code), pollDeviceFlow throws DeviceFlowError with GitHub's error code as the message.

Source

Thrown at packages/core/src/github-auth/device-flow.ts:129

  opts: PollOptions = {}
): Promise<DeviceAccessToken> {
  const sleep = opts.sleep ?? defaultSleep;
  let interval = Math.max(1, intervalSeconds);
  for (;;) {
    if (opts.signal?.aborted) {
      throw new DeviceFlowError('aborted', 'Device flow polling was aborted');
    }
    await sleep(interval * 1000);
    const result = await pollDeviceFlowOnce(clientId, deviceCode);
    if (result.status === 'authorized') return result.token;
    if (result.status === 'pending') continue;
    if (result.status === 'slow_down') {
      // Honor the server's new interval, else keep the current. Floor at 1s so a
      // malformed `interval: 0` can't turn this into a busy loop.
      interval = Math.max(1, result.interval);
      continue;
    }
    throw new DeviceFlowError(result.code);
  }
}

/** Result of a single (non-blocking) device-flow poll. */
export type PollOnceResult =
  | { status: 'pending' }
  | { status: 'slow_down'; interval: number }
  | { status: 'authorized'; token: DeviceAccessToken }
  | { status: 'error'; code: string };

/**
 * One non-blocking poll attempt. Used by the web endpoint (which polls from the
 * browser) and internally by {@link pollDeviceFlow}'s blocking loop.
 */
export async function pollDeviceFlowOnce(
  clientId: string,
  deviceCode: string
): Promise<PollOnceResult> {

View on GitHub (pinned to 0773b97458)

Solutions

  1. Restart startDeviceFlow to get a fresh device/user code and try again
  2. If code is access_denied, ask the user to approve the request next time
  3. If code is authorization_pending/expired, complete the login faster or raise the code lifetime
  4. Match on the specific code and surface a user-friendly message

Example fix

// before
const token = await pollDeviceFlow(clientId, data.device_code, 5);
// after
try {
  const token = await pollDeviceFlow(clientId, data.device_code, 5);
} catch (e) {
  if (e instanceof DeviceFlowError && e.code === 'authorization_pending') {
    return startDeviceFlow(clientId); // fresh code
  }
  throw e;
}
Defensive patterns

Strategy: retry

Try / catch

try { return await pollDeviceFlow(clientId, deviceCode, interval); } catch (e) { if (e instanceof DeviceFlowError && e.code === 'authorization_pending') return restartDeviceFlow(); throw e; }

Prevention

When it happens

Trigger: pollDeviceFlow's pollDeviceFlowOnce returns a status like 'denied' or 'expired' — the user clicked 'I do not authorize', the user code expired, or the wrong code was entered.

Common situations: User takes too long and the device code expires; user denies the authorization request; user types the wrong code; polling continues after the token was already consumed.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/22005360e9701f28. Report an issue: GitHub.