Skip to content

Bedrock provider sends null toolUse.input for no-argument tool calls #8050

@clouatre

Description

@clouatre

Describe the bug

Bedrock's Converse API rejects tool calls when the model invokes a tool with no arguments:

ValidationException: The value at messages.1.content.0.toolUse.input is empty.

To Reproduce

  1. Use the aws_bedrock provider
  2. Resume a session from the session DB where a tool call had null/missing arguments, or switch from Google/Vertex provider to Bedrock mid-session
  3. On the next API call, Bedrock returns ValidationException

The primary path: tool_result_serde.rs:40 maps Value::Null => None during session deserialization, feeding None arguments into the Bedrock format handler. In a pure Bedrock session without resume, from_bedrock_content_block always produces Some(map), so None arguments do not originate from Bedrock responses.


Expected behavior

No-argument tool calls should send {} (empty JSON object) as toolUse.input.


Root cause

In crates/goose/src/providers/formats/bedrock.rs (lines 75 and 90), both ToolRequest and FrontendToolRequest convert arguments via:

.input(to_bedrock_json(&Value::from(call.arguments.clone())))

When call.arguments (Option<JsonObject>) is None, Value::from(None) yields Value::Null, which to_bedrock_json converts to Document::Null. The AWS SDK builder accepts this, but the Bedrock API rejects it.

tool_result_serde.rs:40 is the primary source of None arguments: it explicitly maps Value::Null => None when deserializing tool calls from the session database.

Suggested fix:

let input_val = call.arguments.clone()
    .map(Value::Object)
    .unwrap_or_else(|| Value::Object(Default::default()));

Both ToolRequest (line 75) and FrontendToolRequest (line 90) need this change.


Retry behavior (secondary issue)

The ValidationException for empty input is miscategorized in the error handling chain. In crates/goose/src/providers/bedrock.rs (line 301), unmatched ValidationException variants fall through to the catch-all:

err => ProviderError::ServerError(format!("Failed to call Bedrock: {:?}", err))

ServerError is retryable per should_retry() in crates/goose/src/providers/retry.rs. Retries are futile because the same deserialized None arguments are re-sent each attempt. After exhausting retries, the session is unrecoverable.

This ValidationException is a deterministic client-side serialization bug, not a transient server error. It should either be prevented by the primary fix above, or mapped to a non-retryable error variant (e.g., ExecutionError).


Please provide the following information

  • OS & Arch: macOS (Apple Silicon)
  • Interface: CLI
  • Version: v1.28.0 (also confirmed on current main)
  • Extensions enabled: developer, code-analyze, context7, brave_search, aptu
  • Provider & Model: aws_bedrock / global.anthropic.claude-sonnet-4-6

Additional context

  • The ToolUseBlock API reference documents input as a required field typed as JSON document
  • aws/aws-sdk-php#2962 is the same class of bug in the PHP SDK: empty/null input rejected by the Converse API
  • vercel/ai#5527 discusses defaulting to {} for tools with no parameters in the Vercel AI SDK's Bedrock provider
  • No existing tests cover the None-arguments case

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions