{"record":{"id":"1a06045a871ec280","repo":"coleam00/Archon","slug":"data-error","errorCode":null,"errorMessage":"${data.error}","messagePattern":"\\$\\{data\\.error\\}","errorType":"error_code","errorClass":"DeviceFlowError","httpStatus":null,"severity":"error","filePath":"packages/core/src/github-auth/device-flow.ts","lineNumber":90,"sourceCode":"      const body = (await res.json()) as { error_description?: string; error?: string };\n      detail = body.error_description ?? body.error ?? '';\n    } catch {\n      // Body was not JSON — fall back to the status line only.\n    }\n    throw new DeviceFlowError(\n      'http_error',\n      `GitHub device flow returned HTTP ${res.status}${detail ? `: ${detail}` : ''}`\n    );\n  }\n  return (await res.json()) as T;\n}\n\n/** Step 1: request device + user codes. */\nexport async function startDeviceFlow(clientId: string): Promise<DeviceCodeResponse> {\n  const data = await postForm<DeviceCodeResponse & { error?: string }>(DEVICE_CODE_URL, {\n    client_id: clientId,\n  });\n  if (data.error) throw new DeviceFlowError(data.error);\n  return data;\n}\n\nexport interface PollOptions {\n  signal?: AbortSignal;\n  /** Injectable sleep for deterministic tests. */\n  sleep?: (ms: number) => Promise<void>;\n}\n\nconst defaultSleep = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms));\n\n/**\n * Step 2: poll until the user authorizes. Handles `authorization_pending`\n * (keep waiting) and `slow_down` (back off using the server-supplied interval).\n * Any other `error` is terminal and thrown as a DeviceFlowError.\n */\nexport async function pollDeviceFlow(\n  clientId: string,","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/core/src/github-auth/device-flow.ts#L72-L108","documentation":"startDeviceFlow requests a device and user code from GitHub's OAuth device-flow endpoint. When GitHub responds with an `error` field (e.g. invalid client_id), the library throws DeviceFlowError carrying that exact error code so the caller can surface the OAuth failure verbatim.","triggerScenarios":"Calling startDeviceFlow(clientId) when the GitHub token POST to DEVICE_CODE_URL returns a JSON body with an `error` property (device code endpoint rejects the request).","commonSituations":"Misconfigured or revoked OAuth App client ID; client ID copied from the wrong app; GitHub outages returning error payloads; network proxies injecting error responses.","solutions":["Verify GITHUB_CLIENT_ID matches the OAuth App / GitHub App client ID in developer settings","Catch DeviceFlowError and print its code against GitHub's device-flow error docs (e.g. incorrect_client_id)","Re-create the OAuth app if it was deleted or suspended","Retry later if GitHub is having an incident"],"exampleFix":"// before\nawait startDeviceFlow(process.env.MY_APP_ID!);\n// after\nconst clientId = process.env.GITHUB_CLIENT_ID;\nif (!clientId) throw new Error('GITHUB_CLIENT_ID not set');\nawait startDeviceFlow(clientId);","handlingStrategy":"try-catch","validationCode":"if (!clientId || !/^[A-Za-z0-9]+$/.test(clientId)) throw new Error('Invalid GITHUB_CLIENT_ID before starting device flow');","typeGuard":null,"tryCatchPattern":"try { const dc = await startDeviceFlow(clientId); } catch (e) { if (e instanceof DeviceFlowError) { console.error(`GitHub device code request failed: ${e.code}`); } throw e; }","preventionTips":["Validate the client ID is present and non-empty before calling","Store the client ID in one config location and verify it against the GitHub app settings after changes"],"tags":["oauth","github","device-flow","authentication"],"backgroundTag":"oauth-device-flow-error","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}