{"record":{"id":"b6f83a191a205bdd","repo":"decolua/9router","slug":"device-auth-initiation-failed-error","errorCode":null,"errorMessage":"`Device auth initiation failed: ${error}`","messagePattern":"`Device auth initiation failed: (.+?)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/providers/kilocode.js","lineNumber":16,"sourceCode":"import { KILOCODE_CONFIG } from \"../constants/oauth.js\";\n\nconst kilocode = {\n  config: KILOCODE_CONFIG,\n  flowType: \"device_code\",\n  requestDeviceCode: async (config) => {\n    const response = await fetch(config.initiateUrl, {\n      method: \"POST\",\n      headers: { \"Content-Type\": \"application/json\" },\n    });\n    if (!response.ok) {\n      if (response.status === 429) {\n        throw new Error(\"Too many pending authorization requests. Please try again later.\");\n      }\n      const error = await response.text();\n      throw new Error(`Device auth initiation failed: ${error}`);\n    }\n    const data = await response.json();\n    return {\n      device_code: data.code,\n      user_code: data.code,\n      verification_uri: data.verificationUrl,\n      verification_uri_complete: data.verificationUrl,\n      expires_in: data.expiresIn || 300,\n      interval: 3,\n    };\n  },\n  pollToken: async (config, deviceCode) => {\n    const response = await fetch(`${config.pollUrlBase}/${deviceCode}`);\n    if (response.status === 202) return { ok: false, data: { error: \"authorization_pending\" } };\n    if (response.status === 403) return { ok: false, data: { error: \"access_denied\", error_description: \"Authorization denied by user\" } };\n    if (response.status === 410) return { ok: false, data: { error: \"expired_token\", error_description: \"Authorization code expired\" } };\n    if (!response.ok) return { ok: false, data: { error: \"poll_failed\", error_description: `Poll failed: ${response.status}` } };\n    const data = await response.json();","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/providers/kilocode.js#L1-L34","documentation":"Kilocode's requestDeviceCode treats any non-OK response from POST config.initiateUrl (other than 429) as a fatal initiation failure. The response body text is appended to the message, so the text carries the upstream API's own error detail (auth problems, server errors, malformed requests, outages). This wraps a remote API rejection at the very first step of the device flow.","triggerScenarios":"POST to the Kilocode initiate endpoint returns 4xx/5xx — e.g. Kilocode API outage (5xx), invalid/changed initiateUrl in KILOCODE_CONFIG, network middleware/proxy returning an error page, or API contract changes making the request invalid.","commonSituations":"Kilocode service incident or maintenance window; corporate proxy intercepting HTTPS and returning 502 HTML; stale constants after a Kilocode API version bump; firewall blocking the request with an error response.","solutions":["Read the suffix after 'Device auth initiation failed:' — it contains the upstream response body identifying the real cause","Check Kilocode's service status / retry later if the body indicates a 5xx or HTML error page (proxy/outage)","Verify KILOCODE_CONFIG.initiateUrl in src/lib/oauth/constants/oauth.js still matches the current Kilocode API and update it if the API changed","Test basic connectivity from the host: curl -X POST <initiateUrl> — if that fails, fix proxy/firewall/DNS rather than the app","Initiate the device flow again after resolving; the session was never created so nothing to clean up"],"exampleFix":"// before\nconst dc = await requestDeviceCode('kilocode'); // opaque failure on 5xx\n// after\ntry {\n  const dc = await requestDeviceCode('kilocode');\n} catch (e) {\n  const detail = e.message.replace('Device auth initiation failed: ', '');\n  console.error('Kilocode initiate failed, upstream said:', detail);\n  if (/\\d{3}/.test(detail) && /<html|bad gateway|unavailable/i.test(detail)) {\n    // upstream/proxy outage — surface retry-later to the user\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Reachability pre-check before starting the flow (best-effort):\nasync function canReachKilocode() {\n  try {\n    const r = await fetch(KILOCODE_CONFIG.initiateUrl, { method: 'HEAD' });\n    return r.status < 500; // any structured response means the endpoint is reachable\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  const dc = await requestDeviceCode('kilocode', challenge);\n} catch (e) {\n  if (e.message.startsWith('Device auth initiation failed:')) {\n    const upstream = e.message.slice('Device auth initiation failed:'.length).trim();\n    logger.error('Kilocode initiate rejected by upstream', { upstream });\n    // 5xx/HTML body => transient outage/proxy: allow retry later; 4xx body => config/contract problem: alert\n  }\n  throw e;\n}","preventionTips":["Always log the full message — the upstream response body after the prefix is the real diagnosis","Check Kilocode status/health before enabling the connect flow in automated environments","Pin/verify KILOCODE_CONFIG.initiateUrl after any Kilocode API change","Ensure proxies allow outbound POSTs with JSON content-type to the Kilocode API domain","Distinguish transient (5xx, HTML proxy pages) from permanent (4xx) failures when deciding to retry"],"tags":["oauth","device-code-flow","http-error","network"],"backgroundTag":"upstream-api-error","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}