anomalyco / anomalyco/opencode

Kimi K3: HTTP 400 "assistant message must not be empty" when switching models mid-session

Open
#39,451 3 comments 0 reactions 1 assignee View on GitHub

@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

  1. 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_calls with no text content.
  2. Mid-session, switch the model to Kimi K3 via /models.
  3. Send any message (e.g. "test").
  4. 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 content is empty, even when tool_calls are 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 provider options (baseURL, blacklist/whitelist, options [timeout/chunkTimeout/setCacheKey/headers/apiKey], npm, name, models) include no message-normalization toggle (https://opencode.ai/docs/config).

Workarounds

  • /clear or 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_calls and empty content, send content: 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

Plugins

No response

OpenCode version

1.18.9

Steps to reproduce

No response

Screenshot and/or share link
Image
Operating System

macOs 26.5.1 (25F80)

Terminal

zsh

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.