wavetermdev/waveterm · error
toolResults cannot be empty
Error message
toolResults cannot be empty
What it means
ConvertToolResultsToAnthropicChatMessage converts a slice of AIToolResult into an Anthropic chat message containing tool_result content blocks. The library rejects an empty slice because Anthropic API messages must carry at least one content block; there is nothing meaningful to send for zero tool results. The caller must guarantee at least one tool result before invoking this converter.
Source
Thrown at pkg/aiusechat/anthropic/anthropic-convertmessage.go:750
func convertMessageForAPI(msg anthropicInputMessage) anthropicInputMessage {
// Create a copy of the message
converted := anthropicInputMessage{
Role: msg.Role,
Content: make([]anthropicMessageContentBlock, len(msg.Content)),
}
// Copy each content block and clean it (strips internal fields)
for i, block := range msg.Content {
converted.Content[i] = *block.Clean()
}
return converted
}
// ConvertToolResultsToAnthropicChatMessage converts AIToolResult slice to anthropicChatMessage
func ConvertToolResultsToAnthropicChatMessage(toolResults []uctypes.AIToolResult) (*anthropicChatMessage, error) {
if len(toolResults) == 0 {
return nil, errors.New("toolResults cannot be empty")
}
var contentBlocks []anthropicMessageContentBlock
for _, result := range toolResults {
if result.ToolUseID == "" {
return nil, fmt.Errorf("tool result missing ToolUseID")
}
var content interface{}
var isError bool
if result.ErrorText != "" {
content = result.ErrorText
isError = true
} else {
// Check if text looks like an image data URL
if strings.HasPrefix(result.Text, "data:image/") {View on GitHub (pinned to a4447c1563)
Solutions
- Guard the call site: only call ConvertToolResultsToAnthropicChatMessage when len(toolResults) > 0
- If no tool results exist, skip the tool-result turn entirely and send the next user/assistant message instead
- If tool calls were made but not executed, run them (or synthesize tool_result blocks with an error payload) so the slice is non-empty
- Check upstream logic that builds the toolResults slice for early-return or filtering bugs that drop all entries
Example fix
// before
msg, err := ConvertToolResultsToAnthropicChatMessage(toolResults)
// after
if len(toolResults) == 0 {
return nil // nothing to send; skip tool-result turn
}
msg, err := ConvertToolResultsToAnthropicChatMessage(toolResults) Defensive patterns
Strategy: validation
Validate before calling
if len(toolResults) == 0 {
// skip the tool-result turn entirely
return nil
}
msg, err := ConvertToolResultsToAnthropicChatMessage(toolResults) Prevention
- Never call converters with nil/empty slices; skip the turn instead
- When tool calls exist but fail to execute, synthesize error tool_result blocks so results are non-empty
- Review filtering logic that builds the toolResults slice for cases that drop every entry
When it happens
Trigger: Calling ConvertToolResultsToAnthropicChatMessage(nil) or ConvertToolResultsToAnthropicChatMessage([]uctypes.AIToolResult{}) — i.e. the len(toolResults) == 0 check at line 750. This happens when a tool-execution loop produced no results (e.g. all tool calls were filtered out or execution was skipped) but the code still proceeds to convert.
Common situations: A chat step ends with pending tool calls that were never executed; a batching layer collects results into a slice that ends up empty after deduplication/filtering; tests pass an empty slice; an early error path skipped tool execution but conversion is still attempted.
Related errors
- invalid AIMessage: %w
- ai:model is required
- file part missing url
- file part missing mediaType
- invalid data URL format
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/bae5f095f26cef7d.
Report an issue: GitHub.