fix: Anthropic rejects empty text blocks in assistant history#559
Merged
Conversation
…turns
Anthropic's Messages API rejects text content blocks with empty strings
("messages: text content blocks must be non-empty"). When an assistant
turn has no text and no tool calls, the serializer produced text: ""
which causes a permanent 400 loop — the session is unrecoverable
because every retry sends the same invalid history.
Use a single space instead, satisfying both Anthropic constraints:
non-empty content array and non-empty text block.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Anthropic's Messages API rejects
{"type": "text", "text": ""}with:When an assistant turn has no text and no tool calls (rare but possible — e.g. empty end_turn response), the serializer produces an empty text block as a fallback to satisfy the non-empty content array requirement. This creates a permanent 400 loop: the corrupted history is preserved in the session, so every subsequent prompt on that session sends the same invalid payload and gets the same rejection.
With the session-preservation fix from #544, this is worse — the harness correctly keeps the session alive (pipe is intact), but the session is now permanently poisoned. The event gets requeued with exponential backoff up to 10 times, all failing identically.
Fix
Use
" "(single space) instead of""in the empty-content fallback. Satisfies both Anthropic constraints: non-empty content array and non-empty text block.Changes
crates/sprout-agent/src/llm.rs: 1 character changed (""→" "), plus a comment explaining why.