jlcodes99/cockpit-tools · error
Token 交换失败: status={}, body_len={}
Error message
Token 交换失败: status={}, body_len={} What it means
In exchange_code_for_token_internal, after sending the OAuth authorization code to the provider's token endpoint, the HTTP response status is not a success (2xx). The error is logged with the status code and response body length, and a formatted error is returned to complete_oauth_login. The authorization code could not be exchanged for access/id/refresh tokens.
Source
Thrown at crates/cockpit-core/src/modules/codex_oauth.rs:893
logger::log_info("Codex OAuth 开始交换 Token");
// 官方 authorization-code exchange 使用 raw auth client,不附加运行时 originator headers。
let response = client
.post(TOKEN_ENDPOINT)
.form(¶ms)
.send()
.await
.map_err(|e| format!("Token 请求失败: {}", e))?;
let status = response.status();
let body = response
.text()
.await
.map_err(|e| format!("读取响应失败: {}", e))?;
if !status.is_success() {
logger::log_error(&format!(
"Token 交换失败: status={}, body_len={}",
status,
body.len()
));
return Err(format!(
"Token 交换失败: status={}, body_len={}",
status,
body.len()
));
}
logger::log_info("Codex OAuth Token 交换成功");
let token_response: serde_json::Value =
serde_json::from_str(&body).map_err(|e| format!("解析 Token 响应失败: {}", e))?;
let id_token = token_response
.get("id_token")View on GitHub (pinned to 1ed8b77992)
Solutions
- Restart the OAuth login flow to obtain a fresh authorization code and retry the exchange
- Verify redirect_uri and client parameters match exactly what was used in the authorize request
- Check provider status/endpoint availability if status is 5xx, then retry
- Inspect logs for the status code: 400/401 usually means invalid/expired code or misconfigured client
Defensive patterns
Strategy: retry
Validate before calling
// retry only on transient (5xx) failures; 4xx means the code/session must be redone
fn is_retryable_token_status(status: u16) -> bool { status >= 500 } Try / catch
match start_oauth_login(app).await {
Err(e) if format!("{e}").contains("Token 交换失败") => {
if e.contains("status=5") {
// provider outage: retry after a short backoff with a fresh code
tokio::time::sleep(Duration::from_secs(2)).await;
start_oauth_login(app).await
} else {
// 4xx: invalid/expired code or bad client config — restart flow, verify redirect_uri
Err(e)
}
}
other => other,
} Prevention
- Exchange the authorization code immediately after redirect — codes expire in minutes
- Ensure redirect_uri and client params match the authorize request exactly
- Sync system clock (NTP) to avoid token validation skew
- Never reuse an authorization code; start a fresh login on failure
When it happens
Trigger: Redeeming an expired or already-used authorization code; wrong redirect_uri / client_id in the token request; provider-side 4xx (invalid_grant, invalid_client) or 5xx outage; network proxy returning an error page.
Common situations: User took too long between authorize and exchange so the code expired; clock skew invalidating tokens; provider credentials rotated; OpenAI auth service temporarily down (5xx).
Related errors
- Codex OAuth completed 命令失败: login_id={}, duration_ms={}, err
- OAuth 回调服务器错误: {}
- Codex OAuth 回调超时: login_id={}, callback_url={}, elapsed={}s
- OAuth 流程失败: {}
- OAuth 回调服务器错误: {}
AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05).
Data as JSON: /api/errors/add6bf90bf5d616a.
Report an issue: GitHub.