github/copilot-sdk · error
failed to serialize result
Error message
failed to serialize result: %w
What it means
normalizeResult converts a tool handler's return value into a ToolResult. Results that are not already string/structured get JSON-serialized; if json.Marshal on the result fails, this error is returned. It indicates the handler returned a value that cannot be represented as JSON.
Solutions
- Return JSON-safe data (plain maps/structs with exported, serializable fields) from the handler
- Tag or drop non-serializable struct fields (json:"-")
- Pre-serialize problematic fields yourself (e.g. fmt.Sprint for display) before returning
- If the wrapped error cites an unsupported type, locate and fix that field in the returned value
Example fix
// before
return map[string]any{"file": os.Stdin}, nil // not serializable
// after
return map[string]any{"file": "os.Stdin (descriptor)"}, nil Defensive patterns
Strategy: validation
Validate before calling
// pre-flight in tests: ensure handler results marshal cleanly
b, err := json.Marshal(handlerResult); if err != nil { t.Fatal(err) } Type guard
// Go: reject non-serializable results before returning them
func serializable(v any) error {
_, err := json.Marshal(v)
return err
} Try / catch
// Go
res, err := tool.Invoke(inv)
if err != nil && strings.Contains(err.Error(), "failed to serialize result") {
// handler returned non-JSON value; inspect and fix handler return
} Prevention
- Return plain maps/structs with exported fields from handlers
- Tag non-serializable fields with json:"-"
- Avoid returning runtime handles (files, conns) as results
When it happens
Trigger: A tool handler returns a value containing non-JSON-serializable data (channels, funcs, cycles, NaN/Inf floats) that reaches the default JSON-serialization branch of normalizeResult.
Common situations: Handler accidentally returning a Go struct with a circular reference or func field; returning raw runtime values (e.g. a *os.File, error value with cycles) instead of a plain data structure.
Understand the failure class
Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.
Related errors
- Failed to serialize FFI JSON parameter.
- Expected a non-empty string value when writing
- Failed to serialize tool result
- failed to marshal arguments
- failed to unmarshal arguments into %T
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/06819dee69bb856d.
Report an issue: GitHub.
Appendix: source
Thrown at go/definetool.go:95
}
// ToolResult passes through directly
if tr, ok := result.(ToolResult); ok {
return tr, nil
}
// Strings pass through directly
if str, ok := result.(string); ok {
return ToolResult{
TextResultForLLM: str,
ResultType: "success",
}, nil
}
// Everything else gets JSON-serialized
jsonBytes, err := json.Marshal(result)
if err != nil {
return ToolResult{}, fmt.Errorf("failed to serialize result: %w", err)
}
return ToolResult{
TextResultForLLM: string(jsonBytes),
ResultType: "success",
}, nil
}
// ConvertMCPCallToolResult converts an MCP CallToolResult value (a map or struct
// with a "content" array and optional "isError" bool) into a ToolResult.
// Returns the converted ToolResult and true if the value matched the expected
// shape, or a zero ToolResult and false otherwise.
func ConvertMCPCallToolResult(value any) (ToolResult, bool) {
m, ok := value.(map[string]any)
if !ok {
jsonBytes, err := json.Marshal(value)
if err != nil {
return ToolResult{}, falseView on GitHub (pinned to cd8cf15dc3)