alibaba/open-code-review · error
invalid tool call arguments for %s: %w
Error message
invalid tool call arguments for %s: %w
What it means
Raised while converting OpenAI-style tool calls to the Anthropic message format. Tool-call function arguments arrive as a JSON string and must be unmarshaled into a map; if the string is non-empty but not valid JSON the conversion aborts with this error wrapping the json.Unmarshal failure. A valid-JSON `null` is accepted and treated as an empty input map (Anthropic rejects null input).
Source
Thrown at internal/llm/client.go:1288
case "assistant":
flushToolResults()
// Reuse the native MessageParam whole to preserve thinking blocks
// and signatures. Copy the slice to avoid mutating shared state
// when the cache_control breakpoint writes below.
if native, ok := msg.Native.Payload.(anthropic.MessageParam); ok && len(native.Content) > 0 {
native.Content = append([]anthropic.ContentBlockParamUnion(nil), native.Content...)
messages = append(messages, native)
continue
}
var blocks []anthropic.ContentBlockParamUnion
if s, ok := msg.Content.(string); ok && s != "" {
blocks = append(blocks, anthropic.NewTextBlock(s))
}
for _, tc := range msg.ToolCalls {
argsMap := map[string]any{}
if tc.Function.Arguments != "" {
if err := json.Unmarshal([]byte(tc.Function.Arguments), &argsMap); err != nil {
return anthropic.MessageNewParams{}, fmt.Errorf("invalid tool call arguments for %s: %w", tc.Function.Name, err)
}
if argsMap == nil {
// null arguments → empty map; Anthropic API rejects
// null input (#382). Same guard as llmloop.parseToolArgs.
argsMap = map[string]any{}
}
}
blocks = append(blocks, anthropic.NewToolUseBlock(tc.ID, argsMap, tc.Function.Name))
}
if len(blocks) > 0 {
messages = append(messages, anthropic.NewAssistantMessage(blocks...))
} else {
s, _ := msg.Content.(string)
messages = append(messages, anthropic.NewAssistantMessage(anthropic.NewTextBlock(s)))
}
default:
flushToolResults()
switch content := msg.Content.(type) {View on GitHub (pinned to 5cf97d0d15)
Solutions
- Inspect tc.Function.Arguments and fix the source producing invalid JSON
- Always generate arguments with json.Marshal(map[string]any{...}) rather than string concatenation
- Validate with json.Valid before passing the message through
- Use `null` or an empty object instead of a malformed string for no-argument tool calls
Example fix
// before
args := `{'path': 'x.go'}` // not valid JSON
// after
argsBytes, _ := json.Marshal(map[string]any{"path": "x.go"})
args := string(argsBytes) Defensive patterns
Strategy: validation
Validate before calling
func validToolArgs(args string) bool {
if args == "" || args == "null" { return true }
var m map[string]any
return json.Unmarshal([]byte(args), &m) == nil
} Prevention
- Always build arguments with json.Marshal, never string concatenation
- Run json.Valid() on model-generated arguments before replaying them
- Treat "null" as an empty map explicitly
- Log raw arguments when a parse fails so upstream model bugs are visible
When it happens
Trigger: Building an anthropic.MessageNewParams from a message whose ToolCalls entry has Function.Arguments that is non-empty but not valid JSON — truncated JSON, single quotes, trailing commas, or a model emitting plain text as arguments.
Common situations: Malformed tool-call arguments produced by a model or upstream provider; arguments built by hand without json.Marshal; logs or fixtures pasted back as arguments; truncation at buffer boundaries.
Related errors
- marshal config: %w
- marshal session_end: %w
- parse config: %w
- parse app config: %w
- invalid JSON for llm.extra_body: %w
AI-assisted analysis of alibaba/open-code-review@5cf97d0d15 (2026-09-02).
Data as JSON: /api/errors/859a73db2f99dca4.
Report an issue: GitHub.