Kuberwastaken/claurst · error · anyhow::Error
exchange_code: bad JSON
Error message
exchange_code: bad JSON: {} What it means
The token endpoint returned HTTP success but the response body was not valid JSON matching the expected TokenResponse shape (missing required access_token field, malformed JSON, or an HTML error page with a 200 status). The grant itself may have half-succeeded; the token cannot be deserialized.
Solutions
- Inspect the raw token endpoint response body (capture via logging/proxy) to see what was returned
- Verify the server implements RFC 6749 token responses with an access_token field
- Retry the flow; some servers intermittently return HTML error pages
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at src-rust/crates/mcp/src/oauth.rs:502 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/6a00ac9fc58f2a09.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/mcp/src/oauth.rs:502
.send()
.await
.map_err(|e| anyhow::anyhow!("exchange_code: request failed: {}", e))?;
if !resp.status().is_success() {
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
anyhow::bail!("exchange_code: HTTP {} — {}", status, body);
}
#[derive(serde::Deserialize)]
struct TokenResponse {
access_token: String,
refresh_token: Option<String>,
expires_in: Option<u64>,
scope: Option<String>,
}
let tr: TokenResponse = resp.json().await.map_err(|e| anyhow::anyhow!("exchange_code: bad JSON: {}", e))?;
let expires_at = tr.expires_in.map(|secs| {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs()
+ secs
});
Ok(McpToken {
access_token: tr.access_token,
refresh_token: tr.refresh_token,
expires_at,
scope: tr.scope,
server_name: String::new(), // caller should set this
})
}
View on GitHub (pinned to b0637c97ec)