{"record":{"id":"8c08fb6992f53506","repo":"github/copilot-sdk","slug":"json-schema-serialization-cannot-fail","errorCode":null,"errorMessage":"JSON Schema serialization cannot fail","messagePattern":"JSON Schema serialization cannot fail","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust/src/tool.rs","lineNumber":50,"sourceCode":"/// # Example\n///\n/// ```rust\n/// use github_copilot_sdk::tool::{schema_for, JsonSchema};\n///\n/// #[derive(JsonSchema)]\n/// struct Params {\n///     /// City name\n///     city: String,\n/// }\n///\n/// let schema = schema_for::<Params>();\n/// assert_eq!(schema[\"type\"], \"object\");\n/// assert!(schema[\"properties\"][\"city\"].is_object());\n/// ```\n#[cfg(feature = \"derive\")]\npub fn schema_for<T: schemars::JsonSchema>() -> serde_json::Value {\n    let schema = schemars::schema_for!(T);\n    let mut value = serde_json::to_value(schema).expect(\"JSON Schema serialization cannot fail\");\n    if let Some(obj) = value.as_object_mut() {\n        obj.remove(\"$schema\");\n        obj.remove(\"title\");\n    }\n    value\n}\n\n/// Convert a JSON Schema [`Value`](serde_json::Value) into the\n/// [`Tool::parameters`](crate::types::Tool::parameters) map shape\n/// expected by the protocol.\n///\n/// Panics if the input is not a JSON object — tool parameter schemas\n/// are always top-level objects (`{\"type\": \"object\", ...}`). Pair with\n/// `schema_for` (available with the `derive` feature) or a\n/// `serde_json::json!(...)` literal.\n///\n/// Use [`try_tool_parameters`] when the schema comes from dynamic input and\n/// should return a recoverable error instead of panicking.","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/rust/src/tool.rs#L32-L68","documentation":"schema_for<T> generates a JSON Schema via schemars and serializes it with .expect(), since schemars' generated schema types are always JSON-serializable by construction. A panic here means something in the toolchain broke that invariant — most plausibly NaN/Infinity defaults or a schemars/serde_json version mismatch.","triggerScenarios":"Calling schema_for<T>() on a type whose generated schema contains non-serializable values (NaN/Infinity in default/minimum attributes) or with mismatched schemars/serde_json versions in the dependency graph.","commonSituations":"Custom JsonSchema impls emitting invalid values; cargo dependency resolution picking incompatible schemars 0.8 vs 1.x; user-written derive attributes like #[schemars(default = ...)] returning NaN.","solutions":["Check for NaN/Infinity values returned by #[schemars(default)] or custom JsonSchema impls on T","Align schemars and serde_json versions in Cargo.toml with what the SDK expects","Replace custom JsonSchema impls with standard derives","Bisect by calling schema_for on subfields of T to find the offending type"],"exampleFix":"// before\n#[schemars(default = \"nan_default\")]\nfn nan_default() -> f64 { f64::NAN } // breaks serialization invariant\n// after\n#[schemars(default = \"zero_default\")]\nfn zero_default() -> f64 { 0.0 }","handlingStrategy":"validation","validationCode":"// Rust: before registering\nfn has_json_safe_defaults<T: schemars::JsonSchema>() -> bool { /* audit #[schemars(default)] fns for NaN */ true }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid NaN/Infinity in #[schemars(default)] functions and custom JsonSchema impls","Keep schemars/serde_json versions aligned with the SDK's expectations","Prefer standard derive over hand-written JsonSchema impls","Add a unit test calling schema_for::<T>() for every tool parameter type"],"tags":["rust","serde","json-schema","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}