odysseus-dev/odysseus · error · HTTPException
ChatGPT did not return a complete device code
Error message
ChatGPT did not return a complete device code
What it means
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.
Source
Thrown at routes/chatgpt_subscription_routes.py:118
try:
from routes.model_routes import _invalidate_models_cache
_invalidate_models_cache()
except Exception:
pass
return result
def _start_device_flow(request: Request, _form) -> DeviceFlowStart:
try:
data = chatgpt_subscription.request_device_code()
except Exception as exc:
raise chatgpt_subscription.to_http_exception(exc)
device_auth_id = data.get("device_auth_id")
user_code = data.get("user_code")
if not device_auth_id or not user_code:
raise HTTPException(502, "ChatGPT did not return a complete device code")
verification_uri = data.get("verification_uri") or f"{chatgpt_subscription.CHATGPT_OAUTH_ISSUER}/codex/device"
return DeviceFlowStart(
pending={
"device_auth_id": device_auth_id,
"user_code": user_code,
"owner": get_current_user(request) or None,
},
response={
"user_code": user_code,
"verification_uri": verification_uri,
},
interval=int(data.get("interval") or 5),
expires_in=int(data.get("expires_in") or 900),
)
def _poll_device_flow(_request: Request, pending: Dict) -> DeviceFlowPoll:
try:View on GitHub (pinned to f9235ebbf1)
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.
Defensive patterns
Strategy: retry
Type guard
def is_complete_device_code(data: dict) -> bool:
return bool(data.get('device_auth_id')) and bool(data.get('user_code')) Try / catch
for attempt in range(2):
resp = requests.post(f'{BASE}/api/chatgpt/device/start')
if resp.status_code == 502 and attempt == 0:
time.sleep(1)
continue
resp.raise_for_status()
break Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ChatGPT token response was missing access_token or refresh_t
- Request failed (HTTP ${response.status})
- Unknown device-flow provider: ${provider}
- ${cfg.label} sign-in did not return a poll id
- GitHub device-code request failed (HTTP {status})
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/0be427f839f37d56.
Report an issue: GitHub.