Kuberwastaken/claurst · error
Failed to parse token response
Error message
Failed to parse token response: {} What it means
The token endpoint returned HTTP 2xx but the body could not be deserialized as JSON. The code calls resp.json::<serde_json::Value>() and maps the serde error into this anyhow error. It indicates the successful response was not valid JSON, which is unexpected for a well-behaved OAuth server.
Solutions
- Dump the raw response body and inspect it; look for HTML from a proxy or captive portal.
- Bypass or properly configure the corporate proxy for this host.
- Verify CODEX_TOKEN_URL is the correct OAuth token endpoint and was not changed.
- Retry later if the provider is having an incident.
Defensive patterns
Strategy: try-catch
Validate before calling
// capture raw body first so failures are debuggable
let raw = resp.text().await?;
let body: serde_json::Value = serde_json::from_str(&raw)
.map_err(|e| anyhow!("Failed to parse token response: {} (body: {})", e, &raw[..raw.len().min(200)]))?; Try / catch
// catch serde errors and include the offending body
match serde_json::from_str::<serde_json::Value>(&raw) {
Ok(v) => Ok(v),
Err(e) => Err(anyhow!("non-JSON token response: {}", e)),
} Prevention
- Read the body as text first and log a prefix on parse failure
- Detect HTML responses (starts with '<') and report proxy/captive-portal interference
- Pin and verify the token endpoint URL in configuration
When it happens
Trigger: exchange_code_for_tokens receives a 200 response whose body is HTML (proxy/login portal interstitial), empty, truncated, or otherwise non-JSON, so resp.json().await fails.
Common situations: Corporate proxy rewriting responses with an HTML error/notice page; misconfigured CODEX_TOKEN_URL pointing at an HTML page; captive portal Wi-Fi intercepting HTTPS; server returning a 200 with empty body during partial outage.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Token exchange failed
- No access_token in response
- Token exchange failed
- exchange_code: HTTP
- OAuth metadata parse error
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/14e7d35b53beef15.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/cli/src/codex_oauth_flow.rs:211
];
let resp = client
.post(CODEX_TOKEN_URL)
.form(¶ms)
.send()
.await
.map_err(|e| anyhow!("Failed to exchange code: {}", e))?;
if !resp.status().is_success() {
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
bail!("Token exchange failed ({}): {}", status, body);
}
let body: serde_json::Value = resp
.json()
.await
.map_err(|e| anyhow!("Failed to parse token response: {}", e))?;
let access_token = body["access_token"]
.as_str()
.unwrap_or("")
.to_string();
if access_token.is_empty() {
bail!("No access_token in response");
}
let refresh_token = body["refresh_token"].as_str().map(|s| s.to_string());
let account_id = extract_account_id_from_jwt(&access_token);
Ok(CodexTokens {
access_token,
refresh_token,
account_id,
expires_at: None,
View on GitHub (pinned to b0637c97ec)