{"record":{"id":"29afd4eaa1364c05","repo":"upstash/context7","slug":"err-error-description-err-error-device-toke","errorCode":null,"errorMessage":"err.error_description || err.error || \"Device token poll failed\"","messagePattern":"err\\.error_description \\|\\| err\\.error \\|\\| \"Device token poll failed\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/utils/auth.ts","lineNumber":305,"sourceCode":"    const err = (await response.json().catch(() => ({}))) as TokenErrorResponse;\n    return {\n      status: \"transient\",\n      errorMessage: err.error_description || err.error || `HTTP ${response.status}`,\n    };\n  }\n\n  const err = (await response.json().catch(() => ({}))) as TokenErrorResponse;\n  switch (err.error) {\n    case \"authorization_pending\":\n      return { status: \"pending\" };\n    case \"slow_down\":\n      return { status: \"slow_down\" };\n    case \"access_denied\":\n      return { status: \"denied\" };\n    case \"expired_token\":\n      return { status: \"expired\" };\n    default:\n      throw new Error(err.error_description || err.error || \"Device token poll failed\");\n  }\n}\n","sourceCodeStart":287,"sourceCodeEnd":308,"githubUrl":"https://github.com/upstash/context7/blob/5284672feb575908efead6fcf1b5e542f8d607bb/packages/cli/src/utils/auth.ts#L287-L308","documentation":"`pollDeviceToken` maps RFC 8628 device-flow error codes to poll statuses (authorization_pending, slow_down, access_denied, expired_token) and treats 5xx as transient above. This throw is the default branch: the token endpoint returned a non-ok, non-5xx response whose `error` code the CLI does not recognize, so it throws `error_description || error || \"Device token poll failed\"`.","triggerScenarios":"Polling /api/oauth/device/token with a device_code that was issued for a different client_id or baseUrl (`invalid_grant`); `invalid_client` from a stale CLI_CLIENT_ID; the server introducing a new error code the CLI build predates.","commonSituations":"Device code from a different CLI version or base URL; clock skew or code typed into a different environment; server-side changes to the device flow after an outage.","solutions":["Restart the login flow to get a fresh device_code and user_code","Make sure the whole flow runs against one baseUrl (no mid-flow env changes)","Update the CLI so it knows the latest error codes","Check the message body — it carries the server's own error_description"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Only poll while the device code is still live\nconst deadline = Date.now() + response.expires_in * 1000;\nif (Date.now() >= deadline) throw new Error('device_code already expired — restart login');","typeGuard":"function isKnownDeviceFlowError(e: string): e is 'authorization_pending' | 'slow_down' | 'access_denied' | 'expired_token' {\n  return ['authorization_pending', 'slow_down', 'access_denied', 'expired_token'].includes(e);\n}","tryCatchPattern":"try {\n  const result = await pollDeviceToken(baseUrl, clientId, deviceCode);\n  if (result.status === 'transient') continue; // keep polling\n} catch (error) {\n  // Unknown error code: terminal — restart the whole device flow, do not retry the poll\n  throw new Error(`device flow aborted: ${error instanceof Error ? error.message : error}`);\n}","preventionTips":["Keep baseUrl and client_id constant for the entire device flow","Honor expires_in and stop polling after it passes","Restart login on any unrecognized poll error rather than looping"],"tags":["oauth","device-flow","polling","cli"],"backgroundTag":"oauth-device-code-invalid-grant","analyzedSha":"5284672feb575908efead6fcf1b5e542f8d607bb","analyzedAt":"2026-08-18T18:00:18.510Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}