github/copilot-sdk · error
failed to marshal arguments
Error message
failed to marshal arguments: %w
What it means
The typed tool wrapper converts the JSON-RPC invocation's Arguments (map[string]any) into the tool's typed params struct via a JSON round-trip. If json.Marshal on the arguments map fails, this error is returned. In practice this is rare because the arguments already came from JSON parsing; it guards against values that cannot be serialized (e.g. channels, funcs, or NaN injected programmatically).
Solutions
- Inspect the Arguments map at the call site for non-JSON-serializable values
- Construct invocations only with JSON-safe types (string, number, bool, nil, slices, maps)
- Validate/sanitize arguments before invoking the tool
- The wrapped err names the unsupported type — fix that field specifically
Example fix
// before
inv.Arguments["callback"] = func() {} // not JSON-serializable
// after
// only pass JSON-representable values:
inv.Arguments["mode"] = "sync" Defensive patterns
Strategy: validation
Validate before calling
// ensure all argument values are JSON-serializable before invoking json.Marshal(inv.Arguments) // do a pre-flight marshal in tests
Type guard
// Go: reject values encoding/json cannot serialize
func jsonSafe(v any) bool {
b, err := json.Marshal(v)
return err == nil && b != nil
} Try / catch
// Go
res, err := tool.Invoke(inv)
if err != nil && strings.Contains(err.Error(), "failed to marshal arguments") {
// fix the invocation's Arguments to contain only JSON-safe values
} Prevention
- Only construct Arguments with JSON-representable types
- Add unit tests that round-trip invocations through JSON
- Never inject funcs/channels into Arguments maps
When it happens
Trigger: An invocation whose Arguments map contains values unsupported by encoding/json (func, channel, complex types) — typically only possible when a caller constructs the invocation in Go code rather than receiving it over JSON-RPC.
Common situations: Unit tests or in-process tool invocation passing non-JSON-serializable argument values; programmatic wiring of a tool handler with malformed Arguments.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- failed to unmarshal arguments into %T
- failed to serialize result
- Failed to serialize FFI JSON parameter.
- Failed to apply default value ' + defaultValue + ' for…
- Invalid schema JSON for parameter ' + param.name() + ' in…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/0fcc1e004c6ef0cd.
Report an issue: GitHub.
Appendix: source
Thrown at go/definetool.go:52
return Tool{
Name: name,
Description: description,
Parameters: schema,
Handler: createTypedHandler(handler),
}
}
// createTypedHandler wraps a typed handler function into the standard ToolHandler signature.
func createTypedHandler[T any, U any](handler func(T, ToolInvocation) (U, error)) ToolHandler {
return func(inv ToolInvocation) (ToolResult, error) {
var params T
// Convert arguments to typed struct via JSON round-trip
// Arguments is already map[string]any from JSON-RPC parsing
jsonBytes, err := json.Marshal(inv.Arguments)
if err != nil {
return ToolResult{}, fmt.Errorf("failed to marshal arguments: %w", err)
}
if err := json.Unmarshal(jsonBytes, ¶ms); err != nil {
return ToolResult{}, fmt.Errorf("failed to unmarshal arguments into %T: %w", params, err)
}
result, err := handler(params, inv)
if err != nil {
return ToolResult{}, err
}
return normalizeResult(result)
}
}
// normalizeResult converts any value to a ToolResult.
// Strings pass through directly, ToolResult passes through, and other types
// are JSON-serialized.View on GitHub (pinned to cd8cf15dc3)