Hmbown/CodeWhale · error

Moonshot function parameters failed safe compatibility…

Error message

Moonshot function parameters failed safe compatibility validation: {error}

What it means

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.

Solutions

  1. Read the KimiParameterSchemaError text after the colon - it names the exact rejected construct (e.g. 'unsupported nested allOf composition').
  2. Rewrite the tool's parameters as a plain {"type":"object","properties":{...}} root, flattening composition by hand.
  3. Inline $defs/$ref into literal subschemas before the tool reaches the Kimi route.
  4. Replace const literals with single-value enums and remove conflicting constraints.
  5. Route that tool to a provider whose schema rules accept the original shape, or report the schema shape (not contents) upstream.

Example fix

// before - root composition, rejected: "root must be a JSON object schema"
{ "anyOf": [ { "type": "object", "properties": { "path": { "type": "string" } } },
             { "type": "object", "properties": { "id": { "type": "string" } } } ] }
// after - plain object root, composition flattened manually
{ "type": "object",
  "properties": { "path": { "type": "string" }, "id": { "type": "string" } } }
Defensive patterns

Strategy: validation

Validate before calling

// Rust: dry-run every tool schema against the Kimi sanitizer before building the request
let mut incompatible = Vec::new();
for tool in &catalog {
    let mut candidate = tool.function.parameters.clone();
    if crate::tools::schema_sanitize::sanitize_for_kimi_parameters(&mut candidate).is_err() {
        incompatible.push(tool.name.clone());
    }
}
if !incompatible.is_empty() {
    anyhow::bail!("tools not MFJS-compatible: {}", incompatible.join(", "));
}

Type guard

fn is_kimi_compatible(params: &serde_json::Value) -> bool {
    let mut candidate = params.clone();
    crate::tools::schema_sanitize::sanitize_for_kimi_parameters(&mut candidate).is_ok()
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/64974ef8147a4bb5. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client/chat.rs:932

    };
    mirror_minimax_reasoning_details_for_messages(messages);
}

fn sanitize_moonshot_chat_tools(chat_tools: &mut [Value]) -> Result<()> {
    for tool in chat_tools {
        let Some(function) = tool
            .as_object_mut()
            .and_then(|tool| tool.get_mut("function"))
            .and_then(Value::as_object_mut)
        else {
            continue;
        };
        let Some(parameters) = function.get_mut("parameters") else {
            continue;
        };
        let note = crate::tools::schema_sanitize::sanitize_for_kimi_parameters(parameters)
            .map_err(|error| {
                anyhow::anyhow!(
                    "Moonshot function parameters failed safe compatibility validation: {error}"
                )
            })?;
        if let Some(note) = note {
            let description = function
                .get("description")
                .and_then(Value::as_str)
                .unwrap_or_default();
            let description = if description.is_empty() {
                note
            } else {
                format!("{description} {note}")
            };
            function.insert("description".to_string(), json!(description));
        }
    }
    Ok(())
}

View on GitHub (pinned to 0c42157ee5)