fix(bedrock): non-whitespace placeholder for empty Converse text blocks (salvage #66167) - #67978
Merged
Merged
Conversation
Bedrock Converse rejects text content blocks that are empty OR
whitespace-only (ValidationException: "text content blocks must
contain non-whitespace text"). The prior fix attempt substituted a
single space (" ") for missing content -- but a lone space IS
whitespace, so it was rejected by the exact same validation rule it
was meant to satisfy. This caused a deterministic, unrecoverable
retry-loop failure once any blank/whitespace assistant, tool, or user
turn entered history (most commonly via context-compaction rewriting
a turn to a blank string).
Adds _safe_text()/_EMPTY_TEXT_PLACEHOLDER ("(empty)") and applies it
everywhere a blank text block could reach the wire: user/assistant
content conversion, tool results, the assistant-empty-turn fallback,
and the first/last-message user-alternation padding. System-prompt
blocks are the one exception: blank parts are dropped entirely rather
than placeholder-filled, since a system prompt block should never
carry meaningless placeholder text.
Adds tests/agent/test_bedrock_empty_text_blocks.py (11 tests, was
already present uncommitted -- codifies the exact failing history
from issue #9486 and asserts no blank block ever reaches Bedrock).
Verified against the actual failed request dump from this session
(27-message payload) -- replaying it through the fixed converter now
produces zero blank/whitespace-only blocks.
…text, update stale placeholder assertions Addresses hermes-sweeper review on PR #66167: 1. _convert_content_to_converse() still emitted {"text": part} directly for plain-string items inside a content list (as opposed to {"type": "text"} dicts), bypassing _safe_text() entirely. A whitespace-only string item (e.g. [" "]) could still reach Bedrock as a blank block. Now routed through _safe_text(). 2. tests/agent/test_bedrock_adapter.py::TestEmptyTextBlockFix asserted the pre-fix behavior (whitespace -> literal space " "), contradicting the new _safe_text()/_EMPTY_TEXT_PLACEHOLDER behavior added in 4618095. Updated assertions to expect the non-whitespace placeholder, plus added a regression test for the list-string-item case above.
Collaborator
This was referenced Jul 31, 2026
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.
Summary
Bedrock's Converse path can no longer send whitespace-only text blocks — the API rejects them ("text content blocks must contain non-whitespace text"), and main's lone-space
" "placeholder was itself whitespace, so empty assistant/tool content still 400'd mid-conversation.Salvages the fix half of #66167 (@Polyhistor — both commits cherry-picked with authorship; the PR's context-table half is superseded by the sibling context-lengths PR).
Changes
agent/bedrock_adapter.py:_safe_text()guard routes every content shape (None, empty, whitespace-only, non-string, list items, dict text parts) to a non-whitespace(empty)placeholder in_convert_content_to_conversetests/agent/test_bedrock_empty_text_blocks.py: dedicated 115-line suite; stale lone-space assertions updatedValidation
test_bedrock_adapter.py+test_bedrock_empty_text_blocks.py_convert_content_to_converseCloses #66167 (context-table half superseded; this PR carries the fix half with authorship). Credit: @Polyhistor.
Infographic