googleapis/mcp-toolbox · error
failed to marshal to JSON: %w
Error message
failed to marshal to JSON: %w
What it means
unmarshalProto first json.Marshal's the generic config value (parsed from YAML) before feeding it to protojson.Unmarshal. This error means the marshal step itself failed, which is rare and indicates the value contains a type the standard JSON encoder cannot serialize (e.g. channel, func, or a malformed structure) rather than a schema mismatch.
Source
Thrown at internal/tools/serverlessspark/createbatch/config.go:33
package createbatch
import (
"context"
"encoding/json"
"fmt"
dataprocpb "cloud.google.com/go/dataproc/v2/apiv1/dataprocpb"
"github.com/goccy/go-yaml"
"github.com/googleapis/mcp-toolbox/internal/tools"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
)
// unmarshalProto is a helper function to unmarshal a generic interface{} into a proto.Message.
func unmarshalProto(data any, m proto.Message) error {
jsonData, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("failed to marshal to JSON: %w", err)
}
return protojson.Unmarshal(jsonData, m)
}
type compatibleSource interface {
CreateBatch(context.Context, *dataprocpb.Batch) (map[string]any, error)
}
// Config is a common config that can be used with any type of create batch tool. However, each tool
// will still need its own config type, embedding this Config, so it can provide a type-specific
// Initialize implementation.
type Config struct {
tools.ConfigBase `yaml:",inline"`
Type string `yaml:"type" validate:"required"`
Source string `yaml:"source" validate:"required"`
RuntimeConfig *dataprocpb.RuntimeConfig `yaml:"runtimeConfig"`
EnvironmentConfig *dataprocpb.EnvironmentConfig `yaml:"environmentConfig"`
}View on GitHub (pinned to 8cc6e09de2)
Solutions
- Inspect the wrapped error after 'failed to marshal to JSON:' to see the offending type
- Ensure RuntimeConfig/EnvironmentConfig values come from standard YAML/JSON decoding (maps, slices, scalars)
- If building Config in Go, use JSON-serializable structures or protojson-native types
Example fix
// before
rc := map[string]any{"properties": make(chan int)}
cfg.RuntimeConfig, _ = unmarshalToProto(rc)
// after
rc := map[string]any{"properties": map[string]any{"key": "value"}} Defensive patterns
Strategy: validation
Validate before calling
// Ensure the value is JSON-encodable before handing to NewConfig
if _, err := json.Marshal(runtimeConfigRaw); err != nil {
return fmt.Errorf("runtimeConfig is not JSON-encodable: %w", err)
} Type guard
func isJSONEncodable(v any) bool { _, err := json.Marshal(v); return err == nil } Try / catch
cfg, err := NewConfig(ctx, raw)
if err != nil && strings.Contains(err.Error(), "failed to marshal to JSON") {
log.Fatalf("runtimeConfig/environmentConfig contains non-serializable data: %v", err)
} Prevention
- Only feed standard YAML/JSON-decoded values into NewConfig
- Avoid passing Go-native types (channels, funcs) into proto config helpers
- Round-trip programmatic config values through json.Marshal/Unmarshal to normalize them
When it happens
Trigger: NewConfig calls unmarshalProto with a decoded YAML value for RuntimeConfig or EnvironmentConfig whose underlying data cannot be marshaled by encoding/json (e.g. contains non-serializable Go values injected programmatically).
Common situations: Constructing Config programmatically (not via YAML) and passing unsupported types in RuntimeConfig/EnvironmentConfig; custom YAML decoders producing exotic 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
- failed to marshal result: %w
- operation finished with error but could not marshal error ob
- failed to unmarshal operation bytes: %w
- failed to marshal request: %w
- failed to unmarshal cluster JSON: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/1b38ed50bee4842a.
Report an issue: GitHub.