{"record":{"id":"64974ef8147a4bb5","repo":"Hmbown/CodeWhale","slug":"moonshot-function-parameters-failed-safe-compatibi","errorCode":null,"errorMessage":"Moonshot function parameters failed safe compatibility validation: {error}","messagePattern":"Moonshot function parameters failed safe compatibility validation: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client/chat.rs","lineNumber":932,"sourceCode":"    };\n    mirror_minimax_reasoning_details_for_messages(messages);\n}\n\nfn sanitize_moonshot_chat_tools(chat_tools: &mut [Value]) -> Result<()> {\n    for tool in chat_tools {\n        let Some(function) = tool\n            .as_object_mut()\n            .and_then(|tool| tool.get_mut(\"function\"))\n            .and_then(Value::as_object_mut)\n        else {\n            continue;\n        };\n        let Some(parameters) = function.get_mut(\"parameters\") else {\n            continue;\n        };\n        let note = crate::tools::schema_sanitize::sanitize_for_kimi_parameters(parameters)\n            .map_err(|error| {\n                anyhow::anyhow!(\n                    \"Moonshot function parameters failed safe compatibility validation: {error}\"\n                )\n            })?;\n        if let Some(note) = note {\n            let description = function\n                .get(\"description\")\n                .and_then(Value::as_str)\n                .unwrap_or_default();\n            let description = if description.is_empty() {\n                note\n            } else {\n                format!(\"{description} {note}\")\n            };\n            function.insert(\"description\".to_string(), json!(description));\n        }\n    }\n    Ok(())\n}","sourceCodeStart":914,"sourceCodeEnd":950,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/client/chat.rs#L914-L950","documentation":"Before a request goes to Moonshot/Kimi, sanitize_for_kimi_parameters rewrites every tool's function.parameters into MFJS (Moonshot's JSON Schema subset): the root must flatten to type:\"object\", internal $ref chains are inlined, unsupported keywords are translated or dropped. Constructs the pass cannot transform safely (see the KimiParameterSchemaError enum: unsupported nested allOf, cyclic root reference, const literals, invalid nullable, root not an object schema, resource limits) abort the whole request with this wrapper message. The diagnostic deliberately omits the schema and $ref contents because MCP-supplied tool schemas may contain private data.","triggerScenarios":"A tool whose parameters root is anyOf/allOf/$ref instead of a plain type:\"object\"; nested allOf composition anywhere in the schema; cyclic, unresolved, or non-object root $refs (including $defs chains); const literals or conflicting enum/const constraints; invalid nullable markers; schemas exceeding MFJS resource limits.","commonSituations":"Registering MCP servers that export rich Draft-2020-12 schemas generated from zod/typebox; tools authored for looser OpenAI routes reused on a Kimi route; a codewhale upgrade that tightened MFJS validation.","solutions":["Read the KimiParameterSchemaError text after the colon - it names the exact rejected construct (e.g. 'unsupported nested allOf composition').","Rewrite the tool's parameters as a plain {\"type\":\"object\",\"properties\":{...}} root, flattening composition by hand.","Inline $defs/$ref into literal subschemas before the tool reaches the Kimi route.","Replace const literals with single-value enums and remove conflicting constraints.","Route that tool to a provider whose schema rules accept the original shape, or report the schema shape (not contents) upstream."],"exampleFix":"// before - root composition, rejected: \"root must be a JSON object schema\"\n{ \"anyOf\": [ { \"type\": \"object\", \"properties\": { \"path\": { \"type\": \"string\" } } },\n             { \"type\": \"object\", \"properties\": { \"id\": { \"type\": \"string\" } } } ] }\n// after - plain object root, composition flattened manually\n{ \"type\": \"object\",\n  \"properties\": { \"path\": { \"type\": \"string\" }, \"id\": { \"type\": \"string\" } } }\n","handlingStrategy":"validation","validationCode":"// Rust: dry-run every tool schema against the Kimi sanitizer before building the request\nlet mut incompatible = Vec::new();\nfor tool in &catalog {\n    let mut candidate = tool.function.parameters.clone();\n    if crate::tools::schema_sanitize::sanitize_for_kimi_parameters(&mut candidate).is_err() {\n        incompatible.push(tool.name.clone());\n    }\n}\nif !incompatible.is_empty() {\n    anyhow::bail!(\"tools not MFJS-compatible: {}\", incompatible.join(\", \"));\n}\n","typeGuard":"fn is_kimi_compatible(params: &serde_json::Value) -> bool {\n    let mut candidate = params.clone();\n    crate::tools::schema_sanitize::sanitize_for_kimi_parameters(&mut candidate).is_ok()\n}\n","tryCatchPattern":null,"preventionTips":["Author function.parameters as plain {\"type\":\"object\",\"properties\":{...}} roots - no root anyOf/allOf/$ref.","Inline $defs and $ref chains before exposing tools to Kimi routes.","Avoid const and nested allOf; use single-value enums and flattened properties.","Run the sanitizer as a registration-time check for MCP tools, not at request time."],"tags":["moonshot","kimi","json-schema","tool-calling","mfjs","validation"],"backgroundTag":"tool-schema-validation-failed","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}