Hmbown/CodeWhale · error

Kimi Formula web search requested an unexpected tool

Error message

Kimi Formula web search requested an unexpected tool

What it means

In the Kimi 'Formula' (K3) web-search flow, the model executes a named web-search function fiber; every function call returned must match WEB_SEARCH_FORMULA_FUNCTION. A call with a different (or missing) function name violates the Formula contract, so the client bails instead of executing an unknown function.

Solutions

  1. Verify the request declares only the Formula web-search tool (see formula_web_search_tools) and no other tools
  2. Log the unexpected function name from the response
  3. Update WEB_SEARCH_FORMULA_FUNCTION if the upstream name changed
  4. Retry with a different model or fall back to the non-Formula native search path

Example fix

// before
if name != WEB_SEARCH_FORMULA_FUNCTION {
    bail!("Kimi Formula web search requested an unexpected tool");
}
// after
if name != WEB_SEARCH_FORMULA_FUNCTION {
    tracing::warn!(name, "unexpected Kimi Formula tool; ignoring call");
    continue;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure the Formula request declares only the expected tool
assert_eq!(request_tools.len(), 1, "Formula requests must declare exactly one tool");

Type guard

fn is_formula_call(tc: &Value) -> bool {
    tc.pointer("/function/name").and_then(Value::as_str) == Some(WEB_SEARCH_FORMULA_FUNCTION)
}

Try / catch

match provider.search_formula(req).await {
    Err(e) if e.to_string().contains("unexpected tool") => {
        log::warn!("Formula model requested an unknown function; using builtin search");
        provider.search_builtin(req).await
    }
    other => other,
}

Prevention

When it happens

Trigger: search_formula iterates the model's tool calls and a call's function.name is not WEB_SEARCH_FORMULA_FUNCTION (the call also omits 'function' or 'name' via the earlier .context checks).

Common situations: Kimi K3/Formula API change renaming the search function; the request accidentally advertising extra tools; a gateway rewriting tool payloads; routing a non-Formula model to the Formula search path.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/93e78ccc87d42229. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client/provider_native_search/kimi.rs:189

        };

        reserve_native_search_tool_calls(&mut tool_calls_executed, tool_calls.len())?;
        messages.push(Value::Object(message.clone()));
        for tool_call in tool_calls {
            let id = tool_call
                .get("id")
                .and_then(Value::as_str)
                .context("Kimi Formula web-search call omitted id")?;
            let function = tool_call
                .get("function")
                .and_then(Value::as_object)
                .context("Kimi Formula web-search call omitted function")?;
            let name = function
                .get("name")
                .and_then(Value::as_str)
                .context("Kimi Formula web-search call omitted function name")?;
            if name != WEB_SEARCH_FORMULA_FUNCTION {
                bail!("Kimi Formula web search requested an unexpected tool");
            }
            let arguments = function
                .get("arguments")
                .and_then(Value::as_str)
                .context("Kimi Formula web-search call omitted arguments")?;
            let _: Value = serde_json::from_str(arguments)
                .context("Kimi Formula web-search arguments were not valid JSON")?;
            let fiber = client
                .post_json(
                    &fiber_url,
                    &json!({ "name": name, "arguments": arguments }),
                    &[],
                )
                .await?;
            messages.push(json!({
                "role": "tool",
                "tool_call_id": id,
                "content": formula_fiber_result(&fiber)?,

View on GitHub (pinned to 73e0f67d83)