{"record":{"id":"64aa4c7a191f3129","repo":"can1357/oh-my-pi","slug":"xai-device-code-token-polling-failed-error-inst","errorCode":null,"errorMessage":"xAI device-code token polling failed: ${error instanceof Error ? error.message : String(error)}","messagePattern":"xAI device-code token polling failed: (.+?)","errorType":"exception","errorClass":"AIError.OAuthError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/registry/oauth/xai-oauth.ts","lineNumber":438,"sourceCode":"\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetchImpl(tokenEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t}),\n\t\t\tredirect: \"error\",\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new AIError.LoginCancelledError();\n\t\tthrow new AIError.OAuthError(\n\t\t\t`xAI device-code token polling failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t{ kind: \"polling\", provider: \"xai\", cause: error },\n\t\t);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new AIError.OAuthError(\n\t\t\t`xAI device-code token polling returned invalid JSON: ${\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t}`,\n\t\t\t{ kind: \"polling\", provider: \"xai\", status: response.status, cause: error },\n\t\t);\n\t}\n\n\tif (response.ok) {","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/registry/oauth/xai-oauth.ts#L420-L456","documentation":"Thrown by pollXAIDeviceToken when the fetch call to the xAI token endpoint fails during device-code polling — network errors, DNS failures, connection resets, or the built-in request timeout. The underlying error is attached as `cause`; an aborted caller signal yields LoginCancelledError instead. Distinguishing this from a 200-with-error payload matters: this is a transport-level failure of one poll iteration.","triggerScenarios":"During `credentials` device login, a poll iteration POSTs grant_type=device_code to the token endpoint and fetchImpl rejects: offline, DNS failure, proxy unreachable, TLS reset, or TOKEN_REQUEST_TIMEOUT_MS exceeded; caller's signal not aborted.","commonSituations":"Network drops mid-login while the user waits to authorize in the browser; laptop sleeping between polls; VPN disconnects; proxy timeouts on long polls; DNS flakiness on repeat poll requests.","solutions":["Retry the login — polling repeats until the code expires, and a single failed poll is usually transient; restart `omp` login if it aborts.","Inspect `err.cause` for the root network error (DNS vs TLS vs timeout) and fix accordingly.","Keep the machine awake and the network stable during the device-authorization window.","Check proxy/VPN configuration — polls run repeatedly, so intermittent proxy failures surface here.","If timeouts are frequent on your link, retry from a faster/more stable connection."],"exampleFix":"// before: letting one bad poll kill the flow\nconst result = await xaiProvider.credentials();\n// after: tolerate transient poll failures with backoff\nlet lastErr: unknown;\nfor (let attempt = 0; attempt < 3; attempt++) {\n  try {\n    return await xaiProvider.credentials();\n  } catch (err) {\n    if (err instanceof AIError.LoginCancelledError) throw err;\n    if (err instanceof AIError.OAuthError && err.kind === \"polling\") {\n      lastErr = err;\n      await Bun.sleep(2000 * (attempt + 1));\n      continue;\n    }\n    throw err;\n  }\n}\nthrow lastErr;","handlingStrategy":"retry","validationCode":"// preflight: confirm the token endpoint is reachable before starting the poll loop\nconst probe = await fetch(tokenEndpoint, { method: \"OPTIONS\", signal: AbortSignal.timeout(5000) }).catch(() => null);\nif (!probe) {\n  throw new Error(\"xAI token endpoint unreachable; fix connectivity before device login\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  await xaiProvider.credentials();\n} catch (err) {\n  if (err instanceof AIError.LoginCancelledError) return;\n  if (err instanceof AIError.OAuthError && err.kind === \"polling\" && err.cause) {\n    // one failed poll is usually transient — restart the flow with backoff\n    logger.warn(\"xAI token poll transport failure; retrying login\", { cause: err.cause });\n    await Bun.sleep(3000);\n    return xaiProvider.credentials();\n  }\n  throw err;\n}","preventionTips":["Keep the machine awake and the network connected during the device-authorization window.","On unreliable links, wrap the whole login in a retry-with-backoff wrapper limited to a few attempts.","Check VPN/proxy stability — repeated polls surface intermittent proxy failures.","Inspect err.cause to separate DNS/TLS/timeout causes before changing configuration."],"tags":["network","oauth","xai","device-flow","polling","timeout"],"backgroundTag":"oauth-endpoint-unreachable","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}