{"record":{"id":"88484f88e18e8611","repo":"decolua/9router","slug":"too-many-pending-authorization-requests-please-t","errorCode":null,"errorMessage":"\"Too many pending authorization requests. Please try again later.\"","messagePattern":"\"Too many pending authorization requests\\. Please try again later\\.\"","errorType":"exception","errorClass":"Error","httpStatus":429,"severity":"warning","filePath":"src/lib/oauth/providers/kilocode.js","lineNumber":13,"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\" } };","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/providers/kilocode.js#L1-L31","documentation":"Kilocode's requestDeviceCode POSTs to config.initiateUrl to start a device authorization session. When the Kilocode API answers HTTP 429 (rate limited / too many outstanding pending device authorizations for the account or IP), this specific message is thrown instead of the generic 'Device auth initiation failed'. It is a server-side throttle, not a bug in the caller's parameters.","triggerScenarios":"Calling the Kilocode device-auth initiation (via requestDeviceCode('kilocode', ...) or the dashboard 'Connect Kilocode' flow) while the account/IP already has too many unexpired pending authorization requests, or after repeatedly retrying initiation in a short window.","commonSituations":"Automated retry loops hammering the initiate endpoint after failed polls; shared IP (CI, office NAT) hitting the limit from multiple users; abandoned device sessions accumulating until they expire.","solutions":["Wait (typically minutes) for existing pending device authorizations to expire, then retry once","Stop automatic retry loops on this error — back off exponentially and cap attempts instead of retrying immediately","Reuse the currently pending session: if a verification URL was already issued, have the user complete that one rather than initiating a new session","Contact Kilocode support if the limit persists with no outstanding requests (shared-IP throttling)"],"exampleFix":"// before\nfor (;;) { await requestDeviceCode('kilocode', challenge); } // hammers API, guarantees 429\n// after\ntry {\n  const dc = await requestDeviceCode('kilocode', challenge);\n} catch (e) {\n  if (/Too many pending authorization/.test(e.message)) {\n    await sleep(60000); // back off before a single retry\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"// No client-side check can predict the server-side 429; instead cap concurrency and\n// reuse existing pending sessions before initiating:\nlet pendingKilocodeSession = null;\nasync function initiateOnce() {\n  if (pendingKilocodeSession && Date.now() < pendingKilocodeSession.expiresAt) return pendingKilocodeSession;\n  const dc = await requestDeviceCode('kilocode', challenge);\n  pendingKilocodeSession = { ...dc, expiresAt: Date.now() + (dc.expires_in || 300) * 1000 };\n  return pendingKilocodeSession;\n}","typeGuard":null,"tryCatchPattern":"const delays = [5000, 15000, 60000];\nfor (let i = 0; i < delays.length; i++) {\n  try { return await requestDeviceCode('kilocode', challenge); }\n  catch (e) {\n    if (!/Too many pending authorization/.test(e.message)) throw e;\n    await new Promise(r => setTimeout(r, delays[i])); // bounded backoff, then give up\n  }\n}\nthrow new Error('Kilocode device auth still rate-limited; try again later');","preventionTips":["Never auto-retry initiation in a tight loop — always back off exponentially","Reuse an unexpired pending device session instead of creating a new one per attempt","Avoid initiating from shared IPs (CI pools) where limits are aggregated","Treat this message as transient and surface a 'try again in a few minutes' UI state"],"tags":["oauth","device-code-flow","rate-limit","http-429"],"backgroundTag":"http-429-rate-limited","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}