{"record":{"id":"005d9f70b40cd20f","repo":"tinyhumansai/openhuman","slug":"no-sse-data-frame-found-in-mcp-response-body","errorCode":null,"errorMessage":"No SSE data frame found in MCP response: {body}","messagePattern":"No SSE data frame found in MCP response: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/mcp/http_client/client_helpers.rs","lineNumber":12,"sourceCode":"use super::{McpAuthChallenge, McpRemoteTool, McpSseEvent};\nuse anyhow::Context;\nuse reqwest::header::{HeaderMap, HeaderName, HeaderValue};\nuse serde_json::Value;\nuse std::collections::HashMap;\n\npub(super) fn parse_sse_message(body: &str) -> anyhow::Result<Value> {\n    let events = parse_sse_events(body)?;\n    let event = events\n        .into_iter()\n        .find_map(|event| event.data)\n        .ok_or_else(|| anyhow::anyhow!(\"No SSE data frame found in MCP response: {body}\"))?;\n    Ok(event)\n}\n\n/// Return the first JSON `data:` frame from the **fully-terminated** prefix of a\n/// partially-received SSE buffer, or `None` if no complete event carrying a data\n/// frame has arrived yet.\n///\n/// MCP Streamable HTTP lets a server keep the POST response's SSE stream open\n/// after it has already emitted the single JSON-RPC reply, so reading the whole\n/// body to stream-close (`response.text().await`) stalls every tool call until\n/// the server closes or the request times out — the dominant transport cause of\n/// the multi-minute skill latency in #4195. Reading incrementally and stopping\n/// at the first data frame lets the call return the instant the reply lands.\n///\n/// Only the portion up to the last blank-line event boundary is parsed, so a\n/// half-received final `data:` line is never decoded as truncated JSON.\n/// Keepalive comments and dataless events are skipped (returns `None`, keep\n/// reading). An SSE event terminates on a blank line; `\\r\\n` is normalised to","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/mcp/http_client/client_helpers.rs#L1-L30","documentation":"parse_sse_message found SSE events in the response body but none carried a data frame. Used as the whole-body fallback when a stream ends without a data frame, so the body is included for diagnosis — typically a server that answered plain JSON over an SSE accept header, or an empty keep-alive stream.","triggerScenarios":"Thrown at src/openhuman/mcp/http_client/client_helpers.rs:12 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check the logged body: if it is plain JSON, the server ignored the SSE accept header and should be contacted without SSE","Verify Content-Type of the response matches text/event-stream","Retry — brief streams may close before the first frame flushes"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}