Skip to content

fix(bedrock): sanitize empty text blocks for custom providers and dir…#24743

Open
lovejh99 wants to merge 8 commits into
NousResearch:mainfrom
lovejh99:fix/bedrock-empty-text-blocks
Open

fix(bedrock): sanitize empty text blocks for custom providers and dir…#24743
lovejh99 wants to merge 8 commits into
NousResearch:mainfrom
lovejh99:fix/bedrock-empty-text-blocks

Conversation

@lovejh99

@lovejh99 lovejh99 commented May 13, 2026

Copy link
Copy Markdown

Fixes ValidationException when using custom OpenAI-compatible providers that proxy to AWS Bedrock Converse API, or when using Bedrock directly in multi-turn conversations with empty tool results.

Problem

Bedrock Converse API strictly rejects empty text blocks with the error:
ValidationException: text content blocks must be non-empty

This occurred in two scenarios:

  1. Custom providers (OpenAI format) proxying to Bedrock backend
  2. Direct Bedrock API usage when tool calls return empty strings

The existing fix in bedrock_adapter.py only covered direct Bedrock connections. Custom providers using chat_completions API mode bypassed this sanitization, causing empty tool results to reach Bedrock and trigger validation errors.

Solution

Two-layer defense strategy:

Layer 1: Universal sanitization (run_agent.py)

Added content sanitization in _build_api_kwargs() before all API mode paths:

  • Replaces None/empty/whitespace-only content with single space " "
  • Handles both string content and multimodal content arrays
  • Applies to ALL API modes: chat_completions, anthropic_messages, bedrock_converse, codex_responses, and provider profiles
  • Benefits custom providers transparently

Layer 2: Bedrock-specific handling (agent/bedrock_adapter.py)

Enhanced two functions:

  1. _convert_content_to_converse():

    • Strips whitespace from all text content
    • Filters out empty text blocks instead of keeping them
    • Returns space placeholder when all content is empty
    • Updated docstring to clarify placeholder behavior
  2. Tool result handling in convert_messages_to_converse():

    • Explicit empty-string detection before creating tool result blocks
    • Uses space placeholder for empty/whitespace-only tool results
    • Preserves non-empty strings and JSON-serialized content

Technical Details

Placeholder choice: Single space " " is semantically neutral, minimally intrusive, and consistent with the existing pattern in anthropic_adapter.py (which uses "(no output)" for similar cases).

Compatibility:

  • No impact on non-empty content
  • Existing Bedrock adapter tests pass (30 tests)
  • Existing Bedrock transport tests pass (100 tests)
  • No conflict with existing bedrock_adapter.py safeguards

Testing

Validated against:

  • Multi-turn conversations with empty tool results
  • Custom provider (openapi-ait.ke.com) proxying to Bedrock
  • Direct Bedrock Converse API usage
  • Mixed content with empty and non-empty text blocks

Closes #9486

What does this PR do?

Related Issue

Fixes #

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

How to Test

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform:

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

…ect API

Fixes ValidationException when using custom OpenAI-compatible providers that
proxy to AWS Bedrock Converse API, or when using Bedrock directly in multi-turn
conversations with empty tool results.

## Problem

Bedrock Converse API strictly rejects empty text blocks with the error:
  ValidationException: text content blocks must be non-empty

This occurred in two scenarios:
1. Custom providers (OpenAI format) proxying to Bedrock backend
2. Direct Bedrock API usage when tool calls return empty strings

The existing fix in bedrock_adapter.py only covered direct Bedrock connections.
Custom providers using chat_completions API mode bypassed this sanitization,
causing empty tool results to reach Bedrock and trigger validation errors.

## Solution

Two-layer defense strategy:

### Layer 1: Universal sanitization (run_agent.py)

Added content sanitization in `_build_api_kwargs()` before all API mode paths:
- Replaces None/empty/whitespace-only content with single space " "
- Handles both string content and multimodal content arrays
- Applies to ALL API modes: chat_completions, anthropic_messages,
  bedrock_converse, codex_responses, and provider profiles
- Benefits custom providers transparently

### Layer 2: Bedrock-specific handling (agent/bedrock_adapter.py)

Enhanced two functions:

1. `_convert_content_to_converse()`:
   - Strips whitespace from all text content
   - Filters out empty text blocks instead of keeping them
   - Returns space placeholder when all content is empty
   - Updated docstring to clarify placeholder behavior

2. Tool result handling in `convert_messages_to_converse()`:
   - Explicit empty-string detection before creating tool result blocks
   - Uses space placeholder for empty/whitespace-only tool results
   - Preserves non-empty strings and JSON-serialized content

## Technical Details

**Placeholder choice**: Single space " " is semantically neutral, minimally
intrusive, and consistent with the existing pattern in anthropic_adapter.py
(which uses "(no output)" for similar cases).

**Compatibility**:
- No impact on non-empty content
- Existing Bedrock adapter tests pass (30 tests)
- Existing Bedrock transport tests pass (100 tests)
- No conflict with existing bedrock_adapter.py safeguards

## Testing

Validated against:
- Multi-turn conversations with empty tool results
- Custom provider (openapi-ait.ke.com) proxying to Bedrock
- Direct Bedrock Converse API usage
- Mixed content with empty and non-empty text blocks

Closes NousResearch#9486
@lovejh99 lovejh99 marked this pull request as draft May 13, 2026 02:27
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent loop, run_agent.py, prompt builder labels May 13, 2026
@lovejh99 lovejh99 marked this pull request as ready for review May 13, 2026 08:29
- Resolved conflict in run_agent.py by accepting main's refactoring
- Migrated empty text sanitization logic to agent/chat_completion_helpers.py
- The fix for Bedrock empty text blocks is now properly integrated with the new code structure
@lovejh99 lovejh99 force-pushed the fix/bedrock-empty-text-blocks branch from e74f2b4 to cc9a2f6 Compare May 18, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Bedrock API 400 Error: "text content blocks must be non-empty" when using custom provider

2 participants