{"record":{"id":"e81c7ee466a557eb","repo":"xai-org/grok-build","slug":"32603-e81c7e","errorCode":"-32603","errorMessage":"serialize ext response: {e}","messagePattern":"serialize ext response: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-pager/src/headless/ext_protocol.rs","lineNumber":14,"sourceCode":"//! Decodes the shell's `x.ai/*` extension notifications into the headless [`ExtEvent`] the orchestrator dispatches.\n//! Also answers reverse `ext_method` requests with policy replies.\n//! This module owns the wire envelope shapes and the method-to-event mapping, kept out of `headless.rs`.\n\nuse agent_client_protocol as acp;\nuse xai_acp_lib::{AcpArgsBox, AcpResult};\n\nuse crate::headless::reducer::{Lifecycle, StreamEvent};\n\n/// Serialize a typed ext-method reply; a serialize failure becomes an explicit ACP error so the oneshot is always answered.\nfn ext_response_from<T: serde::Serialize>(value: &T) -> AcpResult<acp::ExtResponse> {\n    serde_json::value::to_raw_value(value)\n        .map(|raw| acp::ExtResponse::new(raw.into()))\n        .map_err(|e| acp::Error::new(-32603, format!(\"serialize ext response: {e}\")))\n}\n\n/// Answer a reverse `ext_method` request without a UI.\n/// Known interaction methods get a policy reply; dropping `response_tx` instead would fail the whole turn with a channel `recv_failed`.\npub(crate) fn reply_headless_ext_method(args: AcpArgsBox<acp::ExtRequest>) {\n    use xai_grok_tools::implementations::grok_build::ask_user_question::AskUserQuestionExtResponse;\n    use xai_grok_tools::implementations::grok_build::exit_plan_mode::ExitPlanModeExtResponse;\n\n    let method = args.request.method.as_ref();\n    // Known methods are answered without parsing params: even a malformed request gets the policy reply rather than a dropped channel\n    let response = match method {\n        // The model sees the tool's NO_OPERATOR_TEXT (headless sessions are non-interactive), not the interactive \"user declined\" cancel text\n        \"x.ai/ask_user_question\" => ext_response_from(&AskUserQuestionExtResponse::Cancelled),\n        \"x.ai/mcp/elicit\" => {\n            use xai_grok_tools::mcp_elicitation::McpElicitExtResponse;\n            ext_response_from(&McpElicitExtResponse::Cancel)\n        }\n        // The model sees \"Your plan has been approved. You can now start coding.\".","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-pager/src/headless/ext_protocol.rs#L1-L32","documentation":"A -32603 internal error from ext_response_from when serde_json::value::to_raw_value cannot serialize the typed ext-method reply (e.g. AskUserQuestionExtResponse). It exists so the response oneshot is always answered with an explicit ACP error instead of silently dropping the sender.","triggerScenarios":"Serializing an ExtResponse payload that serde cannot convert to RawValue — practically only for non-string-map keys (e.g. HashMap with non-string keys), NaN/f64 in strict positions, or a poisoned serializer for exotic types in the response struct.","commonSituations":"Custom response types added to the headless ext protocol containing maps with non-string keys or non-serializable fields; schema changes introducing such fields.","solutions":["Inspect '{e}' for the serde detail naming the unserializable field","Fix the response struct (use string map keys, serializable field types)","Validate the reply type with a round-trip serialize test","Keep ext response payloads plain JSON-compatible"],"exampleFix":"// before\nstruct Reply { meta: std::collections::HashMap<i32, String> }  // non-string keys\n// after\nstruct Reply { meta: std::collections::HashMap<String, String> }","handlingStrategy":"try-catch","validationCode":"// round-trip check the reply type in tests\nlet raw = serde_json::to_value(&reply).expect(\"ext reply must be JSON-serializable\");\nassert!(raw.is_object());","typeGuard":null,"tryCatchPattern":"match ext_response_from(&reply) {\n  Err(e) if e.code == -32603 => eprintln!(\"serialize failed: {}\", e.message),\n  Ok(resp) => send(resp),\n}","preventionTips":["Use only string-keyed maps in ext response structs","Add serde round-trip unit tests for every ExtResponse type","Avoid f64/NaN and non-JSON types in reply payloads"],"tags":["acp","serialization","json","headless"],"backgroundTag":"serialization-failed","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}