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

  1. Return JSON-safe data (plain maps/structs with exported, serializable fields) from the handler
  2. Tag or drop non-serializable struct fields (json:"-")
  3. Pre-serialize problematic fields yourself (e.g. fmt.Sprint for display) before returning
  4. 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

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


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{}, false

View on GitHub (pinned to cd8cf15dc3)