Description
CodeExecutionToolResultBlock.ToParam() produces a malformed CodeExecutionToolResultBlockParam when the API returns a successful code execution result. The stdout, stderr, and return_code fields are dropped during re-serialization (when they contain zero values), causing a 400 from the API on the next agentic-loop iteration.
Error from API:
messages.21.content.1.code_execution_tool_result.content.RequestCodeExecutionToolResultError.type: Input should be 'code_execution_tool_result_error'
(The misleading error name RequestCodeExecutionToolResultError is because with all result fields dropped, the API falls back to parsing the now-empty content against the error-variant schema and fails on its required type discriminator.)
Root cause
In messageutil.go L345-364:
func (r CodeExecutionToolResultBlock) ToParam() CodeExecutionToolResultBlockParam {
var p CodeExecutionToolResultBlockParam
p.Type = r.Type
p.ToolUseID = r.ToolUseID
if r.Content.JSON.ErrorCode.Valid() {
p.Content.OfRequestCodeExecutionToolResultError = &CodeExecutionToolResultErrorParam{
ErrorCode: r.Content.ErrorCode,
}
} else {
p.Content.OfRequestCodeExecutionResultBlock = &CodeExecutionResultBlockParam{
ReturnCode: r.Content.ReturnCode,
Stderr: r.Content.Stderr,
Stdout: r.Content.Stdout,
}
// ...
}
return p
}
CodeExecutionResultBlockParam fields are tagged json:"...,omitzero". When a code execution returns zero/empty values (very common: successful runs often have ReturnCode=0, empty Stderr, or empty Stdout), omitzero drops the fields entirely. The API then rejects the request because the content object becomes {"type": "code_execution_result"} only, which doesn't match any valid variant shape.
Reproduction
- Multi-turn conversation with
claude-opus-4-7 and extended thinking (adaptive mode with display: omitted)
- Trigger built-in
web_search that leads Claude to use code_execution for analysis
- On the next turn (replaying the assistant message containing the
code_execution_tool_result block), API rejects with the error above.
Reliably reproducible in production when Call Face-style code-review agents loop through 20+ tool calls with thinking enabled.
Same class of bug
All three tools share the same pattern: ToParam() unconditionally assigns fields that have omitzero tags, and zero values silently disappear. Suggest auditing all *ToolResultBlock.ToParam() methods for this pattern.
Workaround (adapted from #317)
import "github.com/anthropics/anthropic-sdk-go/packages/param"
content := msg.ToParam().Content
for i, block := range msg.Content {
switch block.AsAny().(type) {
case anthropic.CodeExecutionToolResultBlock,
anthropic.WebSearchToolResultBlock,
anthropic.ToolSearchToolResultBlock:
if i < len(content) {
content[i] = param.Override[anthropic.ContentBlockParamUnion](block.RawJSON())
}
}
}
Environment
- SDK version: v1.37.0 (bug present, confirmed in multi-turn loops)
- Go version: 1.24
- Model: claude-opus-4-7 (triggers this more often due to server-tool + extended thinking integration)
Suggestion
Drop the omitzero tags on required fields in *ResultBlockParam structs, or explicitly set api:"required" and have ToParam() skip the omitzero behavior. A cleaner long-term fix would be for all ToParam() methods on server tool result blocks to use raw JSON passthrough internally (similar to the workaround above) — since the response shape is already server-produced and server-validated.
/cc #242 #317 — same bug class, systematic issue in ToParam() pattern
Description
CodeExecutionToolResultBlock.ToParam()produces a malformedCodeExecutionToolResultBlockParamwhen the API returns a successful code execution result. Thestdout,stderr, andreturn_codefields are dropped during re-serialization (when they contain zero values), causing a 400 from the API on the next agentic-loop iteration.Error from API:
(The misleading error name
RequestCodeExecutionToolResultErroris because with all result fields dropped, the API falls back to parsing the now-emptycontentagainst the error-variant schema and fails on its requiredtypediscriminator.)Root cause
In
messageutil.goL345-364:CodeExecutionResultBlockParamfields are taggedjson:"...,omitzero". When a code execution returns zero/empty values (very common: successful runs often haveReturnCode=0, emptyStderr, or emptyStdout),omitzerodrops the fields entirely. The API then rejects the request because the content object becomes{"type": "code_execution_result"}only, which doesn't match any valid variant shape.Reproduction
claude-opus-4-7and extended thinking (adaptive mode withdisplay: omitted)web_searchthat leads Claude to usecode_executionfor analysiscode_execution_tool_resultblock), API rejects with the error above.Reliably reproducible in production when Call Face-style code-review agents loop through 20+ tool calls with thinking enabled.
Same class of bug
ToolSearchToolResultBlock.ToParam()dropserror_codeWebSearchToolResultBlock.ToParam()same patternAll three tools share the same pattern:
ToParam()unconditionally assigns fields that haveomitzerotags, and zero values silently disappear. Suggest auditing all*ToolResultBlock.ToParam()methods for this pattern.Workaround (adapted from #317)
Environment
Suggestion
Drop the
omitzerotags on required fields in*ResultBlockParamstructs, or explicitly setapi:"required"and haveToParam()skip theomitzerobehavior. A cleaner long-term fix would be for allToParam()methods on server tool result blocks to use raw JSON passthrough internally (similar to the workaround above) — since the response shape is already server-produced and server-validated./cc #242 #317 — same bug class, systematic issue in ToParam() pattern