wavetermdev/waveterm · error

tool result missing ToolUseID

Error message

tool result missing ToolUseID

What it means

Each tool result must reference the tool_use block it responds to via ToolUseID. The Anthropic API requires tool_result blocks to carry a tool_use_id; a result with an empty ToolUseID cannot be mapped and conversion aborts before any API call.

Source

Thrown at pkg/aiusechat/anthropic/anthropic-convertmessage.go:757

	// 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/") {
				// Parse the data URL to extract media type and base64 data
				parts := strings.SplitN(result.Text, ",", 2)
				if len(parts) == 2 {
					// Extract media type from "data:image/png;base64"
					mediaTypePart := strings.TrimPrefix(parts[0], "data:")
					mediaType := strings.Split(mediaTypePart, ";")[0]

View on GitHub (pinned to a4447c1563)

Solutions

  1. Populate ToolUseID from the corresponding tool_use block id in the assistant message
  2. When streaming/iterating tool calls, capture each call's ID before executing the tool
  3. Add a pre-conversion check that every result has a non-empty ToolUseID

Example fix

// before
results := []uctypes.ToolResult{{Content: output}}
// after
results := []uctypes.ToolResult{{ToolUseID: assistantToolUseID, Content: output}}
Defensive patterns

Strategy: validation

Validate before calling

for i, r := range toolResults {
    if r.ToolUseID == "" { return fmt.Errorf("toolResults[%d] missing ToolUseID", i) }
}

Try / catch

blocks, err := anthropic.ConvertToolResultsToAnthropicChatMessage(toolResults)
if err != nil && strings.Contains(err.Error(), "missing ToolUseID") {
    return fmt.Errorf("internal: tool executor did not propagate tool_use id")
}

Prevention

When it happens

Trigger: Calling ConvertToolResultsToAnthropicChatMessage with a tool result entry where the ToolUseID field is the empty string.

Common situations: Constructing tool results manually and forgetting to copy the ID from the assistant's tool_use block; a previous pipeline step dropping the ID; deserialized results missing fields.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/fa7e640fbef1fbac. Report an issue: GitHub.