googleapis/mcp-toolbox · error

failed to marshal result: %w

Error message

failed to marshal result: %w

What it means

After a successful tool run, runInvoke pretty-prints the result with json.MarshalIndent. This error fires if the tool's returned result cannot be serialized to JSON — typically a result containing values Go's encoding/json cannot handle (channels, funcs, cyclic structures, or unsupported custom types) (cmd/internal/invoke/command.go:158-164).

Source

Thrown at cmd/internal/invoke/command.go:161

		return errMsg
	}
	if requiresAuth {
		errMsg := fmt.Errorf("client authorization is not supported")
		opts.Logger.ErrorContext(ctx, errMsg.Error())
		return errMsg
	}

	result, err := tool.Invoke(ctx, src, parsedParams, "")
	if err != nil {
		errMsg := fmt.Errorf("tool execution failed: %w", err)
		opts.Logger.ErrorContext(ctx, errMsg.Error())
		return errMsg
	}

	// Print Result
	output, err := json.MarshalIndent(result, "", "  ")
	if err != nil {
		errMsg := fmt.Errorf("failed to marshal result: %w", err)
		opts.Logger.ErrorContext(ctx, errMsg.Error())
		return errMsg
	}
	fmt.Fprintln(opts.IOStreams.Out, string(output))

	return nil
}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Inspect the tool implementation's Invoke return value and ensure it contains only JSON-serializable types.
  2. For custom tools, convert unsupported fields (time, big numbers, byte slices) to strings or json.RawMessage before returning.
  3. If it's a built-in tool, report/upgrade: this indicates a bug in that tool kind's result shape; try a newer toolbox version.
  4. File an issue with the tool kind and result data if a stock tool reproduces it.

Example fix

// before (custom tool)
func (t *myTool) Invoke(...) (any, error) {
    return map[string]any{"created": someCustomTimeType{}}, nil // unserializable
}
// after
func (t *myTool) Invoke(...) (any, error) {
    return map[string]any{"created": time.Now().UTC().Format(time.RFC3339)}, nil
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Ensure a tool result is JSON-marshalable before relying on CLI output:
func isJSONSafe(v any) bool {
    _, err := json.Marshal(v)
    return err == nil
}

Type guard

func isJSONSerializable(v any) (string, bool) {
    b, err := json.Marshal(v)
    if err != nil { return "", false }
    return string(b), true
}

Try / catch

// When scripting around the CLI, treat any non-zero exit as marshal/other failure and fall back to raw server invocation:
out, err := exec.Command("toolbox", "invoke", tool, params).CombinedOutput()
if err != nil {
    log.Fatalf("invoke failed (possibly non-JSON-serializable result): %s", out)
}

Prevention

When it happens

Trigger: `toolbox invoke <tool>` where the invoked tool kind returns a result object that fails JSON marshaling: a custom/primitive tool returning unserializable data (e.g. non-UTF8 bytes mishandled, maps with non-string keys of unsupported types, cycles).

Common situations: Using a custom tool (via the SDK) whose Invoke returns a struct with unexported cyclic pointers or non-JSON-safe types; a tool returning map[customType]any results; rarely, driver row values wrapped in unsupported types.

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


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/fdc3357954c81347. Report an issue: GitHub.