hermes - 💡(How to fix) Fix [Bug]: Bedrock Converse rejects whitespace-only placeholder ('text content blocks must contain non-whitespace text'); breaks resuming assistant-first history

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

agent/bedrock_adapter.py substitutes a single space ({"text": " "}) as a placeholder for empty/missing message content and for the synthetic "first/last message must be from the user" padding. AWS Bedrock's Converse/ConverseStream, fronting Anthropic Claude models, rejects whitespace-only text blocks:

ValidationException: An error occurred (ValidationException) when calling the ConverseStream operation:
The model returned the following errors: messages: text content blocks must contain non-whitespace text

This is the sequel to #9486. That issue fixed "text content blocks must be non-empty" by replacing empty strings with " ". A single space passes the non-empty check but fails the non-whitespace check, so the mitigation is incomplete and now produces a hard, non-retryable failure.

Error Message

ValidationException: An error occurred (ValidationException) when calling the ConverseStream operation: The model returned the following errors: messages: text content blocks must contain non-whitespace text

Root Cause

In agent/bedrock_adapter.py:

  • convert_messages_to_converse() enforces Converse's "first message must be user" / "last message must be user" rules by injecting {"role": "user", "content": [{"text": " "}]} — a whitespace-only block.
  • _convert_content_to_converse() and the assistant-with-no-content fallback also substitute {"text": " "} for None/empty content, and gate on truthiness (if text) rather than text.strip(), so genuinely whitespace-only text (e.g. "\n") also passes through unsanitized.

Any of these whitespace-only blocks reaching the model triggers the ValidationException, and because it's baked into the request, every retry fails identically.

Fix Action

Fix / Workaround

This is the sequel to #9486. That issue fixed "text content blocks must be non-empty" by replacing empty strings with " ". A single space passes the non-empty check but fails the non-whitespace check, so the mitigation is incomplete and now produces a hard, non-retryable failure.

  • #9486 (the "non-empty" predecessor; the " " mitigation referenced in _convert_content_to_converse's docstring is what this issue addresses)

Code Example

ValidationException: An error occurred (ValidationException) when calling the ConverseStream operation:
The model returned the following errors: messages: text content blocks must contain non-whitespace text

---

from agent.bedrock_adapter import convert_messages_to_converse

# History whose first non-system message is an assistant turn
messages = [
    {"role": "assistant", "content": "Sure, let me look into that."},
    {"role": "user", "content": "thanks"},
]
system, converse = convert_messages_to_converse(messages)
print(converse[0])
# -> {'role': 'user', 'content': [{'text': ' '}]}   # whitespace-only
# Sent to Bedrock ConverseStream -> ValidationException:
#   messages: text content blocks must contain non-whitespace text

---

convert_messages_to_converse([{"role": "user", "content": ""}])
# user content -> [{'text': ' '}]   # whitespace-only -> same ValidationException
RAW_BUFFERClick to expand / collapse

Summary

agent/bedrock_adapter.py substitutes a single space ({"text": " "}) as a placeholder for empty/missing message content and for the synthetic "first/last message must be from the user" padding. AWS Bedrock's Converse/ConverseStream, fronting Anthropic Claude models, rejects whitespace-only text blocks:

ValidationException: An error occurred (ValidationException) when calling the ConverseStream operation:
The model returned the following errors: messages: text content blocks must contain non-whitespace text

This is the sequel to #9486. That issue fixed "text content blocks must be non-empty" by replacing empty strings with " ". A single space passes the non-empty check but fails the non-whitespace check, so the mitigation is incomplete and now produces a hard, non-retryable failure.

Environment

  • hermes-agent v2026.5.29-800-g96ded8831 (commit 96ded8831)
  • Provider: bedrock / bedrock_converse, Anthropic Claude model family, region eu-west-1
  • API: converse_stream()

Root cause

In agent/bedrock_adapter.py:

  • convert_messages_to_converse() enforces Converse's "first message must be user" / "last message must be user" rules by injecting {"role": "user", "content": [{"text": " "}]} — a whitespace-only block.
  • _convert_content_to_converse() and the assistant-with-no-content fallback also substitute {"text": " "} for None/empty content, and gate on truthiness (if text) rather than text.strip(), so genuinely whitespace-only text (e.g. "\n") also passes through unsanitized.

Any of these whitespace-only blocks reaching the model triggers the ValidationException, and because it's baked into the request, every retry fails identically.

Trigger / repro

The leading-user pad fires whenever the converted history does not start with a user message — most commonly when resuming a persisted session whose earliest stored message is an assistant turn (no leading user turn). Minimal repro:

from agent.bedrock_adapter import convert_messages_to_converse

# History whose first non-system message is an assistant turn
messages = [
    {"role": "assistant", "content": "Sure, let me look into that."},
    {"role": "user", "content": "thanks"},
]
system, converse = convert_messages_to_converse(messages)
print(converse[0])
# -> {'role': 'user', 'content': [{'text': ' '}]}   # whitespace-only
# Sent to Bedrock ConverseStream -> ValidationException:
#   messages: text content blocks must contain non-whitespace text

The empty-content path produces the same bad block:

convert_messages_to_converse([{"role": "user", "content": ""}])
# user content -> [{'text': ' '}]   # whitespace-only -> same ValidationException

Suggested fix

Replace every {"text": " "} placeholder in convert_messages_to_converse() (leading/trailing user padding + empty-assistant fallback) and _convert_content_to_converse() (None / empty string / empty text part / no-blocks) with a non-whitespace placeholder such as {"text": "(empty message)"}, and gate on text.strip() instead of truthiness.

This mirrors the already-correct handling in the sibling agent/anthropic_adapter.py::_convert_user_message, which substitutes "(empty message)" and uses .strip() to detect whitespace-only blocks (with regression tests in tests/agent/test_anthropic_adapter.py, e.g. test_whitespace_only_user_message_gets_placeholder). The Bedrock adapter appears to have simply not been brought in line.

Optional hardening: when the converted history starts with an assistant/tool turn, drop the leading orphan run or seed a non-whitespace user turn rather than padding with whitespace.

Related

  • #9486 (the "non-empty" predecessor; the " " mitigation referenced in _convert_content_to_converse's docstring is what this issue addresses)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING