Skip to content

fix(bedrock): replace whitespace-only ' ' placeholder with '(empty message)' in Converse adapter - #39850

Open
HeLLGURD wants to merge 1 commit into
NousResearch:mainfrom
HeLLGURD:fix/bedrock-whitespace-placeholder
Open

fix(bedrock): replace whitespace-only ' ' placeholder with '(empty message)' in Converse adapter#39850
HeLLGURD wants to merge 1 commit into
NousResearch:mainfrom
HeLLGURD:fix/bedrock-whitespace-placeholder

Conversation

@HeLLGURD

@HeLLGURD HeLLGURD commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Bug

�gent/bedrock_adapter.py uses a single space ({"text": " "}) as a placeholder for empty/missing message content and for the synthetic user-padding turns that enforce Converse's strict user/assistant alternation requirement. AWS Bedrock's Converse/ConverseStream API - when fronting Anthropic Claude models - rejects whitespace-only text blocks:

ValidationException: text content blocks must contain non-whitespace text

This is the sequel to #9486. That fix replaced empty strings with " ", which passes the non-empty check but fails the non-whitespace check introduced subsequently by the Converse validation layer. The result is a hard, non-retryable failure that fires every time a persisted session is resumed whose earliest stored message is an assistant turn (triggering the leading-user padding path).

Impact

Every �edrock / �edrock_converse request that hits any of the following paths produces an unrecoverable ValidationException:

  • Resuming a session whose history starts with an assistant message (leading-user pad)
  • None or empty-string message content (_convert_content_to_converse)
  • Whitespace-only text parts ("\n", "\t", etc.) passing the bare-truthiness gate
  • An assistant message with no text and no tool calls (empty-assistant fallback)

Fix

Replace all seven {"text": " "} placeholder occurrences in _convert_content_to_converse() and convert_messages_to_converse() with {"text": "(empty message)"}, mirroring the already-correct handling in �gent/anthropic_adapter.py::_convert_user_message. Also tighten the truthiness gate on individual text parts from ext if text to ext if text.strip() so that genuinely whitespace-only text blocks (e.g. "\n") are also caught and replaced with the non-whitespace placeholder.

No behaviour change for any request that does not hit these paths.

Closes #39829

…ssage)' in Converse adapter

Bedrock's Converse/ConverseStream API rejects text content blocks that contain
only whitespace (ValidationException: 'text content blocks must contain
non-whitespace text'). The previous fix for NousResearch#9486 replaced empty strings with
a single space ' ', which passes the non-empty check but fails the
non-whitespace check.

Replace all seven ' ' placeholder occurrences in _convert_content_to_converse()
and convert_messages_to_converse() with '(empty message)', mirroring the
already-correct handling in anthropic_adapter.py. Also tighten the truthiness
gate on text parts to use text.strip() instead of bare text truthiness so that
genuinely whitespace-only text blocks are also caught.

Closes NousResearch#39829
@alt-glitch alt-glitch added type/bug Something isn't working provider/bedrock AWS Bedrock (boto3, IAM) comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have labels Jun 5, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for isolating the six literal placeholder sites; the reported assistant-first and empty-content failure is still present on current main at agent/bedrock_adapter.py:505-507, :629, and :655-659.

Problems

  • The change does not yet enforce the stated non-whitespace contract for all Converse text blocks. Current paths still pass raw string list items unchanged at agent/bedrock_adapter.py:512, system list text at :578-580, and tool-result content at :586-590. These paths are outside this diff.
  • The PR changes no tests. Current TestEmptyTextBlockFix instead asserts the obsolete space placeholder at tests/agent/test_bedrock_adapter.py:1307-1323.

Suggested changes

  • Add conversion-level regressions asserting no emitted text block (including nested toolResult.content and system blocks) is whitespace-only.
  • Extend the same sanitizer/policy to the remaining paths while preserving tool-result pairing.

Automated hermes-sweeper review.

Comment thread agent/bedrock_adapter.py
@@ -464,7 +465,7 @@ def _convert_content_to_converse(content) -> List[Dict]:
part_type = part.get("type", "")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handles dict-shaped text parts, but _convert_content_to_converse() still appends raw string list entries unchanged on current main (agent/bedrock_adapter.py:512). Please sanitize a content array such as ["\n"] too, and cover it with a regression test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have provider/bedrock AWS Bedrock (boto3, IAM) sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

3 participants