Skip to content

ToolSearchToolResultBlock.ToParam() drops required error_code field via omitzero #317

@sthayduk

Description

@sthayduk

Description

ToolSearchToolResultBlock.ToParam() produces a malformed ToolSearchToolResultBlockParam when the API returns a tool search error. The error_code field is dropped during re-serialization, causing a 400 from the API on the next agentic-loop iteration.

Error from API:

messages.14.content.1.tool_search_tool_result.content.RequestToolSearchToolResultError.error_code: Field required

Root cause

In messageutil.go, the error branch creates a ToolSearchToolResultErrorParam with the ErrorCode value from the response:

func (r ToolSearchToolResultBlock) ToParam() ToolSearchToolResultBlockParam {
    // ...
    if r.Content.JSON.ErrorCode.Valid() {
        p.Content.OfRequestToolSearchToolResultError = &ToolSearchToolResultErrorParam{
            ErrorCode: ToolSearchToolResultErrorCode(r.Content.ErrorCode),
        }
    }
    // ...
}

ToolSearchToolResultErrorParam.ErrorCode is tagged json:"error_code,omitzero". If the ErrorCode value resolves to an empty string (the zero value for the ToolSearchToolResultErrorCode type), omitzero drops the field entirely. The API then rejects the request because error_code is required.

The marshaled JSON ends up as:

{"type": "tool_search_tool_result_error"}

instead of:

{"type": "tool_search_tool_result_error", "error_code": "..."}

Steps to reproduce

  1. Enable tool search with deferred loading (ToolSearchToolRegex20251119)
  2. Register enough tools to exceed the tool search threshold
  3. Run multi-turn conversations where the model triggers tool search
  4. When the API returns a tool_search_tool_result with an error condition, the next API call fails with 400

Workaround

Use raw JSON passthrough for ToolSearchToolResultBlock content blocks instead of relying on ToParam():

import "github.com/anthropics/anthropic-sdk-go/packages/param"

content := msg.ToParam().Content
for i, block := range msg.Content {
    if _, ok := block.AsAny().(anthropic.ToolSearchToolResultBlock); ok && i < len(content) {
        content[i] = param.Override[anthropic.ContentBlockParamUnion](block.RawJSON())
    }
}

Environment

  • SDK version: v1.35.0 (also confirmed in v1.34.0)
  • Go version: 1.24

Related

#242 — same class of bug with WebSearchToolResultBlock.ToParam()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions