anomalyco / anomalyco/opencode
Kimi K3: HTTP 400 "assistant message must not be empty" when switching models mid-session
@jlongster is already working on this.
Since Jul 29, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Description
Summary
When switching to Kimi K3 (Moonshot) mid-session, the next message fails with HTTP 400 because the replayed conversation history contains an assistant message with empty content (a tool-only turn). Kimi K3 rejects empty-content assistant messages; Kimi K2 and other OpenAI-compatible providers tolerate them.
Environment
- opencode:
1.18.9 - Provider: Moonshot AI (
/connect→ Moonshot AI) - Model: Kimi K3 — note: K3 is not yet in the providers docs (only K2 is documented at https://opencode.ai/docs/providers#moonshot-ai)
- OS:
macOS - Switched from: GLM-5.2
Reproduction
- Start a session with any model (e.g. GLM-5.2) and let the assistant perform several tool calls (bash/read/edit) — i.e. produce assistant turns that contain only
tool_callswith no text content. - Mid-session, switch the model to Kimi K3 via
/models. - Send any message (e.g. "test").
- Request fails immediately with HTTP 400.
Expected
The request is sent to Kimi K3 successfully, or opencode normalizes messages that Kimi K3 rejects.
Actual
HTTP 400 - {"error":{"message":"the message at position 31 with role 'assistant' must not be empty","type":"InvalidParameter","param":null,"code":"InvalidParameter"},"request_id":"9da933b5-c932-959d-b81c-5219bbe9e35f"}
The "position 31" assistant message is a tool-only turn (tool calls, no text). opencode serializes it with empty content, and Kimi K3 rejects empty-content assistant messages.
Analysis
- opencode (via the Vercel AI SDK) serializes assistant turns that contain only tool calls as messages with empty
content. - Kimi K3's API is stricter than Kimi K2 / OpenAI / GLM: it rejects assistant messages whose
contentis empty, even whentool_callsare present. - This only surfaces when switching models mid-session (full history replayed) or in long agentic sessions with many tool-only assistant turns.
- No config option exists to normalize/sanitize these messages — the
provideroptions (baseURL,blacklist/whitelist,options[timeout/chunkTimeout/setCacheKey/headers/apiKey],npm,name,models) include no message-normalization toggle (https://opencode.ai/docs/config).
Workarounds
/clearor start a new session before using Kimi K3 (history no longer contains the empty assistant turns).- Use Kimi K2 (documented, tolerates empty content) or another provider until K3 is officially supported.
Suggested fix
- Normalize assistant messages before sending to Kimi/Moonshot: when an assistant message has
tool_callsand emptycontent, sendcontent: null(OpenAI-compatible) or a single-space placeholder instead of an empty string — whichever Kimi K3 accepts. - Make this automatic for the Moonshot provider, or expose a per-provider option (e.g.
options.normalizeEmptyAssistantContent). - Add Kimi K3 to the providers docs / Models.dev metadata once stable.
References
- Providers docs: https://opencode.ai/docs/providers#moonshot-ai (only Kimi K2)
- Config docs: https://opencode.ai/docs/config
Plugins
No response
OpenCode version
1.18.9
Steps to reproduce
No response
Screenshot and/or share link
Operating System
macOs 26.5.1 (25F80)
Terminal
zsh
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.