github/copilot-sdk · error
ExitPlanModeResult serialization cannot fail
Error message
ExitPlanModeResult serialization cannot fail
What it means
When an exit_plan_mode handler returns a result, the library serializes it to JSON with .expect(), asserting that ExitPlanModeResult always serializes successfully (it is a plain struct of serializable fields). Hitting this panic indicates an invariant violation — e.g. a non-serifiable value (map with non-string keys, NaN) smuggled into the result type.
Solutions
- Inspect the handler's return type for values not representable in JSON (non-string keys, NaN/Infinity)
- Change offending fields to JSON-safe types (string keys, Option instead of NaN)
- Switch to serde_json::to_value(...)? handling instead of expect if building dynamic results
- Report/upgrade if the SDK's own ExitPlanModeResult type triggers this
Example fix
// before
let result = handler.handle(sid, data).await; // contains HashMap<MyEnum, f32 with NaN>
serde_json::to_value(result).expect("ExitPlanModeResult serialization cannot fail")
// after
let value = serde_json::to_value(handler.handle(sid, data).await)
.expect("ExitPlanModeResult serialization cannot fail"); // after making fields JSON-safe Defensive patterns
Strategy: type-guard
When it happens
Trigger: A custom ExitPlanModeResult (or extension field) containing values serde_json cannot represent — non-string map keys, f64 NaN/Infinity — reaching exit_plan_handler.handle's return value.
Common situations: Custom handler implementations returning structs with HashMap<NonStringKey, _> or NaN floats; SDK version drift introducing a field that breaks the invariant.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- JSON Schema serialization cannot fail
- tool parameter schema must be a JSON object
- step(" ") journal returned a hit without a result
- Env is not supported with InProcessConnection: the…
- WorkingDirectory is not supported with InProcessConnection…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/49c37e23ba728d1b.
Report an issue: GitHub.
Appendix: source
Thrown at rust/src/session.rs:3097
}
"exitPlanMode.request" => {
let params = request
.params
.as_ref()
.cloned()
.unwrap_or(Value::Object(serde_json::Map::new()));
let data: ExitPlanModeData = match serde_json::from_value(params) {
Ok(d) => d,
Err(e) => {
warn!(error = %e, "failed to deserialize exitPlanMode.request params, using defaults");
ExitPlanModeData::default()
}
};
let rpc_result = if let Some(exit_plan_handler) = handlers.exit_plan_mode.as_ref() {
let result = exit_plan_handler.handle(sid, data).await;
serde_json::to_value(result).expect("ExitPlanModeResult serialization cannot fail")
} else {
serde_json::json!({ "approved": true })
};
let rpc_response = JsonRpcResponse {
jsonrpc: "2.0".to_string(),
id: request.id,
result: Some(rpc_result),
error: None,
};
let _ = client.send_response(&rpc_response).await;
}
"autoModeSwitch.request" => {
let error_code = request
.params
.as_ref()
.and_then(|p| p.get("errorCode"))
.and_then(|v| v.as_str())View on GitHub (pinned to cd8cf15dc3)