{"record":{"id":"0be427f839f37d56","repo":"odysseus-dev/odysseus","slug":"chatgpt-did-not-return-a-complete-device-code","errorCode":null,"errorMessage":"ChatGPT did not return a complete device code","messagePattern":"ChatGPT did not return a complete device code","errorType":"http","errorClass":"HTTPException","httpStatus":502,"severity":"error","filePath":"routes/chatgpt_subscription_routes.py","lineNumber":118,"sourceCode":"    try:\n        from routes.model_routes import _invalidate_models_cache\n\n        _invalidate_models_cache()\n    except Exception:\n        pass\n    return result\n\n\ndef _start_device_flow(request: Request, _form) -> DeviceFlowStart:\n    try:\n        data = chatgpt_subscription.request_device_code()\n    except Exception as exc:\n        raise chatgpt_subscription.to_http_exception(exc)\n\n    device_auth_id = data.get(\"device_auth_id\")\n    user_code = data.get(\"user_code\")\n    if not device_auth_id or not user_code:\n        raise HTTPException(502, \"ChatGPT did not return a complete device code\")\n    verification_uri = data.get(\"verification_uri\") or f\"{chatgpt_subscription.CHATGPT_OAUTH_ISSUER}/codex/device\"\n    return DeviceFlowStart(\n        pending={\n            \"device_auth_id\": device_auth_id,\n            \"user_code\": user_code,\n            \"owner\": get_current_user(request) or None,\n        },\n        response={\n            \"user_code\": user_code,\n            \"verification_uri\": verification_uri,\n        },\n        interval=int(data.get(\"interval\") or 5),\n        expires_in=int(data.get(\"expires_in\") or 900),\n    )\n\n\ndef _poll_device_flow(_request: Request, pending: Dict) -> DeviceFlowPoll:\n    try:","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/chatgpt_subscription_routes.py#L100-L136","documentation":"Raised as HTTP 502 by _start_device_flow when the device-authorization response from the ChatGPT OAuth issuer lacks device_auth_id or user_code. The upstream call succeeded but the payload is incomplete, so the server cannot build a pending flow for the user to approve. It is explicitly a bad-gateway classification: the fault is attributed to the upstream issuer response.","triggerScenarios":"Starting a ChatGPT Subscription connection (GET/POST of the device-flow start endpoint) while the issuer returns an error envelope, changes field names, or the response is truncated/re-serialized by a proxy.","commonSituations":"OpenAI ships a breaking change to the device authorization endpoint; a corporate proxy rewrites the JSON; an outdated bundled version of chatgpt_subscription expects fields the issuer no longer returns; transient issuer degradation.","solutions":["Retry the device-flow start once — transient issuer glitches are the most common cause.","Update the app to the latest release so chatgpt_subscription.request_device_code matches the current issuer response schema.","Inspect server logs for the raw device-code response to see which key is missing (device_auth_id vs user_code points at different upstream changes).","Remove any HTTP proxy between the server and the ChatGPT OAuth issuer and retry."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"def is_complete_device_code(data: dict) -> bool:\n    return bool(data.get('device_auth_id')) and bool(data.get('user_code'))","tryCatchPattern":"for attempt in range(2):\n    resp = requests.post(f'{BASE}/api/chatgpt/device/start')\n    if resp.status_code == 502 and attempt == 0:\n        time.sleep(1)\n        continue\n    resp.raise_for_status()\n    break","preventionTips":["Retry device-flow start once on 502 before surfacing the error — transient issuer glitches are common.","Validate required keys on the issuer response and alert on schema drift.","Keep the OAuth client module updated when the issuer changes response shapes."],"tags":["http-502","oauth","device-flow","chatgpt","upstream"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}