fix(bedrock): reject tool with empty description before calling Converse#126
fix(bedrock): reject tool with empty description before calling Converse#126simon0191 wants to merge 1 commit into
Conversation
Bedrock's Converse API rejects any tool whose description is the empty
string with an opaque ValidationException ("Member must have length
greater than or equal to 1"), failing the entire call. The mapper used
to pass empty descriptions through unchanged, so callers saw a server-
side error that pointed at tool indices rather than tool names.
Validate upfront in mapToolConfig and surface every offender at once so
callers can fix all of them in one pass with a clear, name-keyed error.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code ReviewSummary: This PR adds upfront validation in the Bedrock provider's What works well
Issues / suggestions1. Whitespace-only descriptions are also rejected by Bedrock A description of if strings.TrimSpace(tool.Description) == "" {
missingDesc = append(missingDesc, tool.Name)
}This costs nothing and closes the gap between the validation and the actual Bedrock constraint. 2. Fragile negative assertion in the test assert.NotContains(t, err.Error(), "summarize,")The trailing comma means this assertion passes if assert.NotContains(t, err.Error(), "search")
assert.NotContains(t, err.Error(), "summarize")These are unambiguous as long as no offending tool shares a prefix with a valid tool name (they don't here). 3. Comment verbosity (minor) The 5-line block comment in 4. The sentinel is only attached by VerdictApprove with the whitespace-only description fix strongly recommended (it closes a real gap between the client check and Bedrock's actual constraint) and the test assertion tightened. The core logic and structure are correct. |
|
Found 1 test failure on Blacksmith runners: Failure
|
|
@claude im wondering whether we should do the check at tool registration time. Would it make sense to require this for all tools across providers? Breaking changes / behaviors are still acceptable |
Should empty-description validation move to tool registration?
Short answer: yes, move it to Here's the full analysis: How tools flow today
Why registration time is better
The fail-fast argument is strong: if a tool has no description, it's a configuration error, not a runtime error. Catching it at What to change
One consideration:
|
|
hah i had exactly same thought @weeco . agree, it should be done at registration time. |
|
i digged a bit deeper, and maybe it's the wrong call to reject empty desc always.. IMHO would not be right call to reject at registration time, the runtime fix is cleaner. LGTM |
| for _, tool := range tools { | ||
| if tool.Description == "" { | ||
| missingDesc = append(missingDesc, tool.Name) | ||
| } | ||
| } | ||
|
|
||
| if len(missingDesc) > 0 { | ||
| return nil, fmt.Errorf("bedrock: every tool must have a non-empty description; missing on: %s", strings.Join(missingDesc, ", ")) | ||
| } |
There was a problem hiding this comment.
@simon0191 I was bothered by this solution and did some research. I noticed:
- Bedrock / AWS itself claims the tool description is NOT required, but when provided it can't be empty, see: https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ToolSpecification.html
- This leads me to believe that this is the problem - we should omit it instead of setting an empty
aws.String()
Have you tried this and see if that works?
Summary
descriptionis the empty string with an opaqueValidationException(Member must have length greater than or equal to 1), failing the entire call. The mapper used to pass empty descriptions through unchanged, so callers got a server-side error that pointed at tool indices (toolConfig.tools.12.member.toolSpec.description) rather than tool names — hard to map back to source for an agent that mixes MCP-derived and subagent-as-tool entries.mapToolConfignow validates upfront and returns one error listing every offender by name, e.g.bedrock: every tool must have a non-empty description; missing on: subagent_a, subagent_b. Errors bubble up wrapped inllm.ErrRequestMapping.agent.New()would crashloop agents that work fine on those providers.Context
Hit in production by an AI agent using subagents whose
Subagent.descriptionwas empty (proto schema marks itOPTIONALwith nomin_len). On the first Bedrock call the whole request failed; the cloudv2 side will land a separate proto-level fix to makedescriptionnon-empty for new data, but this client-side preflight gives every existing caller a useful error today.Test plan
go test ./providers/bedrock/...— full provider suite passesgolangci-lint run ./providers/bedrock/...— cleanTestRequestMapper_EmptyToolDescriptionasserts: error wrapsllm.ErrRequestMapping, both empty-description tools are named in the message, valid tools are not flagged🤖 Generated with Claude Code