{"record":{"id":"038155365f6e3f30","repo":"tinyhumansai/openhuman","slug":"mcp-delete-failed-with","errorCode":null,"errorMessage":"MCP DELETE failed with {}","messagePattern":"MCP DELETE failed with (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"src/openhuman/mcp/http_client/client.rs","lineNumber":451,"sourceCode":"        }\n        parse_sse_events(&text)\n    }\n\n    pub async fn close_session(&self) -> anyhow::Result<()> {\n        let session_id = self.state.lock().session_id.clone();\n        let Some(session_id) = session_id else {\n            return Ok(());\n        };\n        let response = self\n            .http\n            .delete(&self.endpoint)\n            .header(HEADER_SESSION_ID, session_id)\n            .send()\n            .await?;\n        if !(response.status().is_success()\n            || response.status() == reqwest::StatusCode::METHOD_NOT_ALLOWED)\n        {\n            anyhow::bail!(\"MCP DELETE failed with {}\", response.status());\n        }\n        let mut state = self.state.lock();\n        state.initialized = false;\n        state.session_id = None;\n        state.initialize = None;\n        state.cached_tools.clear();\n        Ok(())\n    }\n\n    async fn send_notification(&self, method: &str, params: Value) -> anyhow::Result<()> {\n        let body = json!({\n            \"jsonrpc\": \"2.0\",\n            \"method\": method,\n            \"params\": params,\n        });\n        let request = self\n            .http\n            .post(&self.endpoint)","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/mcp/http_client/client.rs#L433-L469","documentation":"`close_session` sends `DELETE` to the MCP endpoint with the stored `Mcp-Session-Id`; any status other than success or 405 Method Not Allowed bails with this message. 405 is explicitly tolerated because servers are not required to implement session deletion — so this error means the server understood the DELETE and rejected it (e.g. 404 unknown session, 401 expired token), not that it merely lacks the endpoint.","triggerScenarios":"Closing a session whose id the server already expired/evicted (404); closing with an expired or revoked OAuth token (401); gateway errors (502/503) at teardown time.","commonSituations":"Cleanup at app shutdown racing the server's own session GC; teardown after the SSE stream already broke; load-balanced deployments where the DELETE lands on a node that never held the session.","solutions":["Treat close-session failure as best-effort: log and continue — servers expire sessions on their own anyway.","On 401, refresh the token first if you need a clean close; otherwise skip.","On 5xx from a proxy, retry once with backoff or ignore."],"exampleFix":"// before\nclient.close_session().await?;\n\n// after — teardown is best-effort\nif let Err(e) = client.close_session().await {\n    tracing::debug!(\"mcp session close best-effort failed: {e}\");\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = client.close_session().await {\n    tracing::debug!(\"best-effort session close failed: {e}\"); // never fail teardown on this\n}","preventionTips":["Treat session close as optional cleanup; servers expire sessions independently.","Do not gate shutdown paths on close_session succeeding.","Refresh auth before close only if a clean close is a hard requirement."],"tags":["mcp","http","session","cleanup"],"backgroundTag":"http-error-response","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}