{"record":{"id":"f0115e5006ed3c1a","repo":"decolua/9router","slug":"provider-providername-does-not-support-device","errorCode":null,"errorMessage":"`Provider ${providerName} does not support device code flow`","messagePattern":"`Provider (.+?) does not support device code flow`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/oauth/providers/index.js","lineNumber":144,"sourceCode":"    : provider.config;\n\n  const tokens = await provider.exchangeToken(config, code, redirectUri, codeVerifier, state, meta || {});\n\n  let extra = null;\n  if (provider.postExchange) {\n    extra = await provider.postExchange(tokens);\n  }\n\n  return provider.mapTokens(tokens, extra);\n}\n\n/**\n * Request device code (for device_code flow)\n */\nexport async function requestDeviceCode(providerName, codeChallenge, options) {\n  const provider = getProvider(providerName);\n  if (provider.flowType !== \"device_code\") {\n    throw new Error(`Provider ${providerName} does not support device code flow`);\n  }\n  return await provider.requestDeviceCode(provider.config, codeChallenge, options || {});\n}\n\n/**\n * Poll for token (for device_code flow)\n * @param {string} providerName - Provider name\n * @param {string} deviceCode - Device code from requestDeviceCode\n * @param {string} codeVerifier - PKCE code verifier (optional for some providers)\n * @param {object} extraData - Extra data from device code response (e.g. clientId/clientSecret for Kiro)\n */\nexport async function pollForToken(providerName, deviceCode, codeVerifier, extraData) {\n  const provider = getProvider(providerName);\n  if (provider.flowType !== \"device_code\") {\n    throw new Error(`Provider ${providerName} does not support device code flow`);\n  }\n\n  const result = await provider.pollToken(provider.config, deviceCode, codeVerifier, extraData);","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/providers/index.js#L126-L162","documentation":"requestDeviceCode(providerName, codeChallenge, options) first resolves the provider via getProvider, then asserts provider.flowType === 'device_code' before delegating to provider.requestDeviceCode. If the provider exists but uses a different flow (e.g. authorization_code_pkce), it cannot initiate a device-code session, so this error is thrown instead of calling an undefined/incorrect method.","triggerScenarios":"Calling requestDeviceCode for a provider whose module sets flowType to 'authorization_code_pkce' or another non-device flow — e.g. requestDeviceCode('claude', challenge) or requestDeviceCode('github', challenge), where the correct entry point is generateAuthData + the browser auth URL flow instead.","commonSituations":"A generic OAuth client that always uses the device-code path regardless of provider; UI or CLI offering 'sign in with device code' for every provider; provider migrations that changed flowType; confusing providers with similar names (kilocode is device_code, but most others are not).","solutions":["Check provider.flowType (via getProvider(name).flowType) before choosing the flow; only call requestDeviceCode when it equals 'device_code'","For flowType 'authorization_code_pkce' (or default), use generateAuthData(providerName, redirectUri, meta) to get authUrl/state/codeVerifier and complete the browser + callback/exchangeTokens flow instead","If the provider should genuinely support device code, verify you are targeting the right provider name (e.g. kilocode, kiro) rather than a PKCE-only one","Update calling code/UI to branch on flowType rather than hardcoding the device-code path"],"exampleFix":"// before\nconst dc = await requestDeviceCode('claude', codeChallenge); // throws: claude is not device_code\n// after\nimport { getProvider, requestDeviceCode, generateAuthData } from '@/lib/oauth/providers/index.js';\nconst p = getProvider('claude');\nconst auth = p.flowType === 'device_code'\n  ? await requestDeviceCode('claude', codeChallenge)\n  : await generateAuthData('claude', redirectUri); // use auth.authUrl in browser flow","handlingStrategy":"type-guard","validationCode":"import { getProvider } from '@/lib/oauth/providers/index.js';\nfunction supportsDeviceCode(name) {\n  try { return getProvider(name).flowType === 'device_code'; } catch { return false; }\n}\n// if (!supportsDeviceCode(name)) use generateAuthData() browser flow instead","typeGuard":"function isDeviceCodeProvider(name) {\n  const p = getProvider(name);\n  return p != null && p.flowType === 'device_code' && typeof p.requestDeviceCode === 'function';\n}","tryCatchPattern":"try {\n  const dc = await requestDeviceCode(name, challenge);\n} catch (e) {\n  if (e.message.includes('does not support device code flow')) {\n    const auth = await generateAuthData(name, redirectUri);\n    // redirect user to auth.authUrl instead\n    return;\n  }\n  throw e;\n}","preventionTips":["Branch OAuth UI/logic on provider.flowType, never on a hardcoded provider list","Check flowType before calling requestDeviceCode/pollForToken anywhere in a shared client","Remember only device_code providers (kilocode, kiro, github, etc.) support these APIs","Write a small helper exposing flow capabilities instead of duplicating getProvider calls"],"tags":["oauth","device-code-flow","unsupported-operation"],"backgroundTag":"oauth-flow-not-supported","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}