Hmbown/CodeWhale · error

invalid SSE JSON: {e}

Error message

invalid SSE JSON: {e}

What it means

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.

Source

Thrown at crates/tui/src/client/anthropic.rs:781

            unsafe {
                if let Some(map) = (*pointer).as_object_mut() {
                    map.remove("cache_control");
                }
            }
        }
    }
}

/// Convert one SSE `data:` payload into a [`StreamEvent`], normalizing usage
/// objects to the #2961 convention. Returns `None` for ignorable payloads.
fn convert_anthropic_sse_data(data: &str) -> Option<Result<StreamEvent>> {
    let trimmed = data.trim();
    if trimmed.is_empty() {
        return None;
    }
    let mut value: Value = match serde_json::from_str(trimmed) {
        Ok(value) => value,
        Err(e) => return Some(Err(anyhow::anyhow!("invalid SSE JSON: {e}"))),
    };

    match value.get("type").and_then(Value::as_str) {
        Some("message_start") => {
            if let Some(usage) = value
                .get_mut("message")
                .and_then(|message| message.get_mut("usage"))
            {
                *usage = json!(parse_anthropic_usage(usage));
            }
        }
        Some("message_delta") => {
            if let Some(usage) = value.get_mut("usage") {
                *usage = json!(parse_anthropic_usage(usage));
            }
        }
        // Tolerate unknown event types (e.g. future additions) silently.
        Some(known)

View on GitHub (pinned to 8880682c63)

Solutions

  1. Retry the request once — truncated frames are usually transient
  2. Capture the raw line (debug logging) to confirm whether the payload is truncated JSON or something else entirely
  3. Bypass or disable any intermediary proxy between the client and api.anthropic.com
  4. If the same payload fails deterministically, report it upstream — the provider is emitting invalid JSON
Defensive patterns

Strategy: try-catch

Type guard

fn is_invalid_sse_json(err: &anyhow::Error) -> bool {
    err.to_string().starts_with("invalid SSE JSON")
}

Try / catch

match stream.next().await {
    Some(Err(e)) if is_invalid_sse_json(&e) => {
        log::warn!("dropping turn, upstream sent bad SSE JSON: {e}");
        retry_whole_request().await;
    }
    other => { /* forward */ }
}

Prevention

When it happens

Trigger: 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.

Common situations: Corporate proxies or gateways buffering/mangling SSE; transient network corruption; a provider-side serialization bug emitting a malformed frame.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/e8c2aaa541265dc9. Report an issue: GitHub.