{"record":{"id":"e8c2aaa541265dc9","repo":"Hmbown/CodeWhale","slug":"invalid-sse-json-e","errorCode":null,"errorMessage":"invalid SSE JSON: {e}","messagePattern":"invalid SSE JSON: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client/anthropic.rs","lineNumber":781,"sourceCode":"            unsafe {\n                if let Some(map) = (*pointer).as_object_mut() {\n                    map.remove(\"cache_control\");\n                }\n            }\n        }\n    }\n}\n\n/// Convert one SSE `data:` payload into a [`StreamEvent`], normalizing usage\n/// objects to the #2961 convention. Returns `None` for ignorable payloads.\nfn convert_anthropic_sse_data(data: &str) -> Option<Result<StreamEvent>> {\n    let trimmed = data.trim();\n    if trimmed.is_empty() {\n        return None;\n    }\n    let mut value: Value = match serde_json::from_str(trimmed) {\n        Ok(value) => value,\n        Err(e) => return Some(Err(anyhow::anyhow!(\"invalid SSE JSON: {e}\"))),\n    };\n\n    match value.get(\"type\").and_then(Value::as_str) {\n        Some(\"message_start\") => {\n            if let Some(usage) = value\n                .get_mut(\"message\")\n                .and_then(|message| message.get_mut(\"usage\"))\n            {\n                *usage = json!(parse_anthropic_usage(usage));\n            }\n        }\n        Some(\"message_delta\") => {\n            if let Some(usage) = value.get_mut(\"usage\") {\n                *usage = json!(parse_anthropic_usage(usage));\n            }\n        }\n        // Tolerate unknown event types (e.g. future additions) silently.\n        Some(known)","sourceCodeStart":763,"sourceCodeEnd":799,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client/anthropic.rs#L763-L799","documentation":"A non-empty `data:` payload on the Anthropic stream failed `serde_json::from_str`. The client fails closed: it yields an error instead of silently skipping the frame, because dropping a payload could lose content deltas or usage accounting.","triggerScenarios":"A proxy or intermediary truncates or rewrites the SSE payload; the upstream sends a non-JSON `data:` line; bytes are corrupted in transit so the line is no longer parseable JSON.","commonSituations":"Corporate proxies or gateways buffering/mangling SSE; transient network corruption; a provider-side serialization bug emitting a malformed frame.","solutions":["Retry the request once — truncated frames are usually transient","Capture the raw line (debug logging) to confirm whether the payload is truncated JSON or something else entirely","Bypass or disable any intermediary proxy between the client and api.anthropic.com","If the same payload fails deterministically, report it upstream — the provider is emitting invalid JSON"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_invalid_sse_json(err: &anyhow::Error) -> bool {\n    err.to_string().starts_with(\"invalid SSE JSON\")\n}","tryCatchPattern":"match stream.next().await {\n    Some(Err(e)) if is_invalid_sse_json(&e) => {\n        log::warn!(\"dropping turn, upstream sent bad SSE JSON: {e}\");\n        retry_whole_request().await;\n    }\n    other => { /* forward */ }\n}","preventionTips":["Avoid SSE-mangling intermediaries (buffering proxies, transcoding gateways) on the Anthropic route","Retry once on JSON parse failures — truncation is usually transient","Log the raw failing line before giving up so the failure is reportable"],"tags":["anthropic","sse","json","parsing"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}