Hmbown/CodeWhale · error

responses JSON body

Error message

responses JSON body

What it means

This `expect` panics when `serde_json::from_slice` cannot parse the recorded Responses request body, aborting with 'responses JSON body' at crates/tui/src/client.rs:7920. It verifies the client sent a valid JSON object to the `{base}/responses` endpoint; unparseable bytes mean the request serialization is broken or the recorded body is not what the client sent.

Solutions

  1. Dump `String::from_utf8_lossy(&requests[0].body)` to inspect the raw payload
  2. Confirm the client serializes the Responses payload as one JSON object with `model` and `input` fields
  3. Rule out compression or chunked-recording artifacts in the mock
  4. Fix the serializer so the body parses cleanly

Example fix

// before
let body: Value = serde_json::from_slice(&requests[0].body).expect("responses JSON body");
// after
let raw = String::from_utf8_lossy(&requests[0].body).to_string();
let body: Value = serde_json::from_str(&raw)
    .unwrap_or_else(|e| panic!("responses JSON body ({e}): {raw}"));
Defensive patterns

Strategy: validation

Validate before calling

let raw = String::from_utf8_lossy(&bytes);
let v: serde_json::Value = serde_json::from_str(&raw)
    .expect("responses request body must be valid JSON");
assert!(v.get("input").is_some());

Type guard

fn as_json(bytes: &[u8]) -> Option<serde_json::Value> {
    serde_json::from_slice(bytes).ok()
}

Try / catch

let body: Value = serde_json::from_slice(&bytes)
    .unwrap_or_else(|e| panic!("responses JSON body: {e}; raw: {}", String::from_utf8_lossy(&bytes)));

Prevention

When it happens

Trigger: Calling `serde_json::from_slice(&requests[0].body)` on a Responses-format request whose body is empty, truncated, SSE-encoded, or otherwise not a single JSON object.

Common situations: The Responses serializer emits an `input` array but a bug concatenates fragments; the mock records chunked/stream bytes as-is; a middleware rewrites or compresses the body before recording.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/363324edf0d6dd49. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client.rs:7920

            offerings,
        });

        let mut client = codewhale_client(&server, "openai/gpt-5.6");
        assert_eq!(client.wire_format, WireFormat::Responses);
        client.retry.enabled = false;
        let response = client
            .create_message(minimal_zen_request("openai/gpt-5.6"))
            .await
            .expect("Codewhale responses request should succeed");

        // Responses usage arrives on the terminal `response.completed` event —
        // the dialect's equivalent of chat's `stream_options.include_usage`.
        assert_eq!(response.usage.input_tokens, 3);
        assert_eq!(response.usage.output_tokens, 1);
        let requests = server.received_requests().await.expect("recorded request");
        assert_eq!(requests.len(), 1);
        assert_codewhale_bearer(&requests[0]);
        let body: Value = serde_json::from_slice(&requests[0].body).expect("responses JSON body");
        assert_eq!(
            body.get("model").and_then(Value::as_str),
            Some("openai/gpt-5.6")
        );
        assert!(body.get("input").is_some(), "Responses body: {body}");
        assert!(body.get("messages").is_none(), "Responses body: {body}");

        crate::provider_catalog_live::reset_cache_for_test();
        crate::provider_lake::clear_live_snapshot();
    }

    fn opencode_zen_client(server: &MockServer, model: &str) -> CodewhaleClient {
        let config = Config {
            provider: Some("opencode-zen".to_string()),
            providers: Some(ProvidersConfig {
                opencode_zen: ProviderConfig {
                    api_key: Some("zen-test-key".to_string()),
                    base_url: Some(server.uri()),

View on GitHub (pinned to 73e0f67d83)