Summary
Following the documented web-search flow ( Use Kimi API's Internet Search Functionality - Kimi API Platform ) — declare the $web_search builtin_function tool, then echo the tool call’s arguments back verbatim in a role: "tool" message — always fails on kimi-k3 with:
HTTP 400 {"error":{"message":"Invalid request: tokenization failed","type":"invalid_request_error"}}
The byte-identical request works correctly on kimi-k2.6: the search results are injected server-side (round-2 prompt_tokens jumps from ~60 to ~8,700) and the model answers with live web data. On kimi-k3 the second request never succeeds, so web search is unusable on k3.
Note: the docs specifically recommend kimi-k3 for web search because of its 1M context window.
Reproduction (Node 18+, no dependencies)
const KEY = process.env.MOONSHOT_API_KEY;
const TOOLS = [{ type: "builtin_function", function: { name: "$web_search" } }];
async function call(model, messages) {
const res = await fetch("https://api.moonshot.ai/v1/chat/completions", {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ model, messages, max_tokens: 8192, tools: TOOLS }),
});
return { status: res.status, body: await res.json() };
}
for (const model of ["kimi-k2.6", "kimi-k3"]) {
const userMsg = { role: "user", content: "What is today's date and the weather in Camden, NJ? Use web search." };
const r1 = await call(model, [userMsg]);
const msg = r1.body.choices[0].message; // finish_reason: "tool_calls"
const tc = msg.tool_calls[0]; // type: "builtin_function", args: {"search_result":{"search_id":...},"usage":{...}}
const r2 = await call(model, [
userMsg,
{ role: "assistant", content: msg.content ?? "", tool_calls: msg.tool_calls },
{ role: "tool", tool_call_id: tc.id, name: tc.function.name, content: tc.function.arguments },
]);
console.log(model, "round2:", r2.status, r2.body?.error?.message ?? r2.body.usage);
}
Observed output (2026-07-23):
kimi-k2.6 round2: 200 { prompt_tokens: 8695, completion_tokens: 2017, ... } <- search results injected, correct live answer
kimi-k3 round2: 400 Invalid request: tokenization failed
What was ruled out
All of the following round-2 variants on kimi-k3 also return 400 tokenization failed:
-
assistant message with
content: ""vs. content field omitted entirely -
tool message with and without the
namefield -
tool message content = full
argumentsstring vs. only thesearch_resultobject vs. empty string -
indexadded to the echoed tool_call -
toolsarray omitted from the round-2 request
The only variant that returns 200 is rewriting the echoed tool_call’s type: "builtin_function" to type: "function" — but then the search results are not injected (round-2 prompt_tokens stays ~250 and the model reports the tool result is empty), so it is not a workaround.
Round-1 always succeeds on both models (tool call emitted, search executed and billed — arguments.usage.total_tokens reports ~2,700–8,600 tokens).
Environment
-
Endpoint:
https://api.moonshot.ai/v1/chat/completions -
Models:
kimi-k3(fails),kimi-k2.6(works) -
Date observed: 2026-07-23, reproduced consistently across ~8 attempts and 3 different queries
-
Failure is immediate (~1s), suggesting request validation/tokenization of the echoed
builtin_functionhistory rather than a search-expansion timeout