{"record":{"id":"895bc3c06af4a515","repo":"Hmbown/CodeWhale","slug":"chat-json-body","errorCode":null,"errorMessage":"chat JSON body","messagePattern":"chat JSON body","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client.rs","lineNumber":7809,"sourceCode":"                    \"finish_reason\": \"stop\"\n                }],\n                \"usage\": {\"prompt_tokens\": 1, \"completion_tokens\": 1, \"total_tokens\": 2}\n            })))\n            .expect(1)\n            .mount(&server)\n            .await;\n\n        let client = codewhale_client(&server, \"deepseek/deepseek-v4-pro\");\n        assert_eq!(client.wire_format, WireFormat::ChatCompletions);\n        client\n            .create_message(minimal_zen_request(\"deepseek/deepseek-v4-pro\"))\n            .await\n            .expect(\"Codewhale chat request should succeed\");\n\n        let requests = server.received_requests().await.expect(\"recorded request\");\n        assert_eq!(requests.len(), 1);\n        assert_codewhale_bearer(&requests[0]);\n        let body: Value = serde_json::from_slice(&requests[0].body).expect(\"chat JSON body\");\n        // Model ids reach the account API exactly as its catalog returns them.\n        assert_eq!(\n            body.get(\"model\").and_then(Value::as_str),\n            Some(\"deepseek/deepseek-v4-pro\")\n        );\n    }\n\n    #[tokio::test]\n    async fn codewhale_messages_request_carries_the_account_bearer_not_x_api_key() {\n        let server = MockServer::start().await;\n        Mock::given(method(\"POST\"))\n            .and(path(\"/v1/messages\"))\n            .respond_with(ResponseTemplate::new(200).set_body_json(json!({\n                \"id\": \"msg_cw\",\n                \"type\": \"message\",\n                \"role\": \"assistant\",\n                \"content\": [{\"type\": \"text\", \"text\": \"ok\"}],\n                \"model\": \"anthropic/claude-sonnet-5\",","sourceCodeStart":7791,"sourceCodeEnd":7827,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/client.rs#L7791-L7827","documentation":"This is a Rust `expect` panic on `serde_json::from_slice`: the test sent a chat request to a mock server, read the recorded request body back, and JSON deserialization failed, so the process aborts with message 'chat JSON body'. The library/test throws it because a chat-completions request body that should be valid JSON was not parseable, meaning the client serialized something malformed or the recorded bytes were truncated/corrupt.","triggerScenarios":"Calling `serde_json::from_slice(&requests[0].body)` in crates/tui/src/client.rs:7809 when the client under test produced a body that is not valid JSON — e.g. a serializer bug, partial write, or binary/gzip bytes recorded instead of raw JSON.","commonSituations":"A wire-format change makes the client emit non-JSON (e.g. SSE lines or form-encoded data) on the chat endpoint; a mock server records compressed bytes; a test asserts on a request that was never fully received.","solutions":["Print `String::from_utf8_lossy(&requests[0].body)` before parsing to see the actual bytes","Confirm the client is using the Chat Completions wire format, not Responses or AnthropicMessages, for this endpoint","Check that no compression/middleware transformed the recorded body","Fix the serializer so the body is a single valid JSON object"],"exampleFix":"// before\nlet body: Value = serde_json::from_slice(&requests[0].body).expect(\"chat JSON body\");\n// after\nlet raw = String::from_utf8_lossy(&requests[0].body).to_string();\nlet body: Value = serde_json::from_str(&raw)\n    .unwrap_or_else(|e| panic!(\"chat JSON body ({e}): {raw}\"));","handlingStrategy":"validation","validationCode":"let raw = String::from_utf8_lossy(&body_bytes);\nif serde_json::from_str::<serde_json::Value>(&raw).is_err() {\n    panic!(\"recorded body is not valid JSON: {raw}\");\n}","typeGuard":"fn is_json_object(bytes: &[u8]) -> Option<serde_json::Value> {\n    serde_json::from_slice(bytes).ok()\n}","tryCatchPattern":"let body: Value = serde_json::from_slice(&bytes)\n    .unwrap_or_else(|e| panic!(\"chat JSON body: {e}; raw: {}\", String::from_utf8_lossy(&bytes)));","preventionTips":["Inspect raw request bytes before asserting on parsed JSON","Keep one wire format per test so serializer mismatches are obvious","Disable compression middleware in mock servers used for body assertions"],"tags":["rust","json","http-test"],"backgroundTag":"json-parse-error","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}