Empty message content causes Anthropic API errors during compaction
Description
During compaction, Anthropic API returns:
messages.9: all messages must have non-empty content except for the optional final assistant message
Root Cause Analysis
After investigating the storage data, found the following message structure in the problematic session:
[0] user | parts: text
[1] assistant | parts: step-start, tool (completed), step-finish ← NO TEXT
[2] assistant | parts: step-start, tool (completed), step-finish ← NO TEXT, consecutive
[3] assistant | parts: step-start, tool (completed), step-finish ← NO TEXT, consecutive
[4] assistant | parts: step-start, text, step-finish
[5] user | parts: text
...
Key observations:
- Messages [1], [2], [3] are consecutive assistant messages with only tool calls (no text)
-
step-finishpart type is not handled intoModelMessage()(lines 480-537) - The filter on line 541 passes these messages because they have
tool-*parts (not juststep-start)
The Conversion Pipeline
In packages/opencode/src/session/message-v2.ts:
// Line 541
return convertToModelMessages(result.filter((msg) => msg.parts.some((part) => part.type !== "step-start")))
The convertToModelMessages from AI SDK (ai package) then converts UIMessage[] to ModelMessage[].
Hypothesis: When convertToModelMessages processes consecutive assistant messages with tool calls, it may:
- Create synthetic user messages for tool results
- These synthetic messages might end up empty in certain edge cases
- Or the merging logic creates an empty content array
Affected Code
-
packages/opencode/src/session/message-v2.ts:421-542—toModelMessage()function - Called from
packages/opencode/src/session/compaction.ts
Questions
- How does
convertToModelMessageshandle consecutive assistant messages with tool calls? - Should
toModelMessage()merge consecutive assistant messages before passing toconvertToModelMessages? - Should there be validation after
convertToModelMessagesto filter out empty messages?
Reproduction
Session with multiple consecutive assistant messages containing only tool calls (no text parts) followed by compaction trigger.
OpenCode version
1.0.209
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
Xubuntu 22.04
Terminal
ghostty
This issue might be a duplicate of existing issues. Please check:
- #5028: Call Missing content in messages: text content blocks must be non-empty - similar API error about empty message content during message processing
- #5187: Ollama: User message content arrives as empty array - model cannot see user input - related issue with empty message content in the message pipeline
- #6068: [BUG]: Auto compaction not triggering reliably with Anthropic models - compaction-related issue with Anthropic API errors
Feel free to ignore if none of these address your specific case.
Can u share a session u got this error w/?
Simply run this:
opencode export > session.json
And send the session
+1 I've had to stop using Opus in opencode because of this :(
Can u plz send a session :)
Can't really since I was working on something personal, but I was around 137 messages in, latest Opencode version as of today, using the oh-my-opencode plugin, when it suddenly just came up with this error pattern, no matter how many undos I tried. I reinstalled and on a new session it is somehow is fixed for now? :shrug:
This should be fixed