{"record":{"id":"73e6a7666b6baa28","repo":"Kuberwastaken/claurst","slug":"exchange-code-http","errorCode":null,"errorMessage":"exchange_code: HTTP {} — {}","messagePattern":"exchange_code: HTTP (.+?) — (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-rust/crates/mcp/src/oauth.rs","lineNumber":491,"sourceCode":"    let client = reqwest::Client::new();\n    let params = [\n        (\"grant_type\", \"authorization_code\"),\n        (\"code\", code),\n        (\"code_verifier\", verifier),\n        (\"redirect_uri\", redirect_uri),\n    ];\n\n    let resp = client\n        .post(token_endpoint)\n        .form(&params)\n        .send()\n        .await\n        .map_err(|e| anyhow::anyhow!(\"exchange_code: request failed: {}\", e))?;\n\n    if !resp.status().is_success() {\n        let status = resp.status();\n        let body = resp.text().await.unwrap_or_default();\n        anyhow::bail!(\"exchange_code: HTTP {} — {}\", status, body);\n    }\n\n    #[derive(serde::Deserialize)]\n    struct TokenResponse {\n        access_token: String,\n        refresh_token: Option<String>,\n        expires_in: Option<u64>,\n        scope: Option<String>,\n    }\n\n    let tr: TokenResponse = resp.json().await.map_err(|e| anyhow::anyhow!(\"exchange_code: bad JSON: {}\", e))?;\n\n    let expires_at = tr.expires_in.map(|secs| {\n        std::time::SystemTime::now()\n            .duration_since(std::time::UNIX_EPOCH)\n            .unwrap_or_default()\n            .as_secs()\n            + secs","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/mcp/src/oauth.rs#L473-L509","documentation":"The OAuth authorization-code token exchange POST returned a non-success HTTP status. The library surfaces the status code and the raw response body so the caller can see the token endpoint's error (e.g. invalid_grant) instead of an opaque failure.","triggerScenarios":"exchange_code (called from run_mcp_auth_session) POSTs the authorization code to the token endpoint and receives any HTTP status where !status.is_success().","commonSituations":"Authorization code expired or was already redeemed (refresh of the page double-submits); wrong client_id/client_secret; redirect_uri in the exchange doesn't match the one used in the authorize request; token endpoint URL misconfigured or provider outage (5xx).","solutions":["Restart the full OAuth flow to get a fresh authorization code (codes are single-use and short-lived)","Compare the client_id, client_secret, and redirect_uri sent to the token endpoint with the provider's registered values","Read the body in the message for the provider's error code (e.g. invalid_grant, invalid_client) and fix accordingly","If 5xx, retry later or check the provider's status page"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match run_mcp_auth_session(server).await {\n    Err(e) if e.to_string().starts_with(\"exchange_code: HTTP\") => {\n        // log body; if invalid_grant, restart the full authorize flow\n    }\n    other => other?,\n}","preventionTips":["Never reuse or refresh authorization codes — they are single-use","Keep client_id/secret/redirect_uri consistent between authorize and token requests","Exchange the code immediately after redirect; codes expire within minutes"],"tags":["oauth","http","token-exchange","network"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}