{"record":{"id":"8d5bbe7f692b4fd7","repo":"can1357/oh-my-pi","slug":"device-authorization-response-missing-required-fie","errorCode":null,"errorMessage":"Device authorization response missing required fields","messagePattern":"Device authorization response missing required fields","errorType":"validation","errorClass":"AIError.OAuthError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/registry/oauth/openai-codex.ts","lineNumber":272,"sourceCode":"\t\tbody: JSON.stringify({ client_id: CLIENT_ID }),\n\t\tsignal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS),\n\t});\n\n\tif (!initResponse.ok) {\n\t\tthrow new AIError.OAuthError(`Device authorization initiation failed: ${initResponse.status}`, {\n\t\t\tkind: \"device-auth\",\n\t\t\tstatus: initResponse.status,\n\t\t});\n\t}\n\n\tconst initData = (await initResponse.json()) as {\n\t\tdevice_auth_id?: string;\n\t\tuser_code?: string;\n\t\tinterval?: string | number;\n\t};\n\n\tif (!initData.device_auth_id || !initData.user_code) {\n\t\tthrow new AIError.OAuthError(\"Device authorization response missing required fields\", { kind: \"validation\" });\n\t}\n\n\tconst userCode = initData.user_code;\n\tconst pollIntervalMs =\n\t\t(typeof initData.interval === \"number\"\n\t\t\t? initData.interval\n\t\t\t: parseInt(String(initData.interval ?? \"5\"), 10) || 5) *\n\t\t\t1000 +\n\t\tDEVICE_POLL_SAFETY_MARGIN_MS;\n\n\tctrl.onAuth?.({\n\t\turl: DEVICE_AUTH_URL,\n\t\tinstructions: `Enter code: ${userCode}`,\n\t});\n\n\tctrl.onProgress?.(`Waiting for browser authorization (code: ${userCode})…`);\n\n\tfor (let poll = 0; poll < DEVICE_MAX_POLLS; poll++) {","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/registry/oauth/openai-codex.ts#L254-L290","documentation":"Thrown by loginOpenAICodexDevice when the device-authorization initiation returned HTTP 200 but the JSON payload lacks the required device_auth_id or user_code fields. Without these the CLI can neither display the code for the user nor poll for the token, so it fails fast with kind='validation'.","triggerScenarios":"OpenAI returns a 200 response whose body is an error object, a different schema (renamed fields after an API change), or an empty/HTML body misinterpreted as JSON — e.g. an intercepted response from a proxy or captive portal.","commonSituations":"Outdated CLI after OpenAI renamed device-auth response fields; network middleware (corporate proxy, antivirus) returning a 200 error page; OpenAI returning 200-wrapped errors under load.","solutions":["Update the CLI so the expected field names match the current OpenAI device-auth API","Inspect what the endpoint actually returns (curl with the same payload) to spot proxies or schema changes","Disable/bypass intercepting proxies or VPNs and retry the login","If OpenAI wrapped an error in a 200 body, wait and retry or check OpenAI status"],"exampleFix":"null","handlingStrategy":"validation","validationCode":"// probe the device-auth endpoint shape before the full login\nconst res = await fetch(DEVICE_AUTH_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: CLIENT_ID }) });\nconst body = await res.json().catch(() => null);\nif (!body || typeof body.device_auth_id !== 'string' || typeof body.user_code !== 'string') {\n  throw new Error('Unexpected device-auth response shape — update CLI or check proxy interference');\n}","typeGuard":"function isDeviceAuthInit(d: unknown): d is { device_auth_id: string; user_code: string; interval?: string | number } {\n  const v = d as Record<string, unknown> | null;\n  return !!v && typeof v.device_auth_id === 'string' && typeof v.user_code === 'string';\n}","tryCatchPattern":"try {\n  const auth = await loginOpenAICodexDevice();\n} catch (e) {\n  if (e instanceof AIError.OAuthError && e.kind === 'validation' && e.message.includes('Device authorization response')) {\n    // update CLI / bypass proxy / retry\n  } else throw e;\n}","preventionTips":["Update the CLI to track OpenAI device-auth schema changes","Bypass intercepting proxies, VPNs, or captive portals that return 200 error pages","Retry once on transient 200-wrapped errors under OpenAI load","Validate responses with a type guard in wrappers around the login flow"],"tags":["oauth","openai-codex","device-flow","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}