googleapis/mcp-toolbox · error

failed to marshal param to JSON: %w

Error message

failed to marshal param to JSON: %w

What it means

convertParamToJSON is a Go template helper that marshals a parameter value to a JSON-formatted string via json.Marshal. json.Marshal only fails for values it cannot encode — channels, funcs, maps with non-string keys, cyclic structures — so this error indicates a template parameter holds an unmarshalable value.

Source

Thrown at internal/util/parameters/common.go:76

	case "boolean":
		tempSlice := make([]bool, len(s))
		for j, item := range s {
			b, ok := item.(bool)
			if !ok {
				return nil, fmt.Errorf("expected item at index %d to be boolean, got %T", j, item)
			}
			tempSlice[j] = b
		}
		typedSlice = tempSlice
	}
	return typedSlice, nil
}

// convertParamToJSON  is a Go template helper function to convert a parameter to JSON formatted string.
func convertParamToJSON(param any) (string, error) {
	jsonData, err := json.Marshal(param)
	if err != nil {
		return "", fmt.Errorf("failed to marshal param to JSON: %w", err)
	}
	return string(jsonData), nil
}

// PopulateTemplateWithJSON populate a Go template with a custom `json` array formatter
func PopulateTemplateWithJSON(templateName, templateString string, data map[string]any) (string, error) {
	return PopulateTemplateWithFunc(templateName, templateString, data, template.FuncMap{
		"json": convertParamToJSON,
	})
}

// PopulateTemplate populate a Go template with no custom formatters
func PopulateTemplate(templateName, templateString string, data map[string]any) (string, error) {
	return PopulateTemplateWithFunc(templateName, templateString, data, nil)
}

// PopulateTemplateWithFunc populate a Go template with provided functions
func PopulateTemplateWithFunc(templateName, templateString string, data map[string]any, funcMap template.FuncMap) (string, error) {

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Inspect the parameter map and remove/replace the unmarshalable value (channel, func, cyclic ref)
  2. Convert custom map key types to string keys before templating
  3. Ensure parameters originate from decoded request data (JSON-safe types)
  4. Log the marshalled type (%T) to pinpoint which param fails

Example fix

// before
data["cb"] = func() {} // unmarshalable
result, err := PopulateTemplateWithJSON("t", tmpl, data)
// after
data["cb"] = nil
result, err := PopulateTemplateWithJSON("t", tmpl, data)
Defensive patterns

Strategy: validation

Validate before calling

func jsonSafe(v any) error {
    _, err := json.Marshal(v)
    return err
}
// call jsonSafe(param) for each template data value before templating

Type guard

func isJSONMarshalable(v any) bool {
    return json.Valid(mustMarshal(v)) || marshalableKind(v)
}
func marshalableKind(v any) bool {
    switch v.(type) {
    case chan struct{}, func():
        return false
    }
    return true
}

Try / catch

out, err := PopulateTemplateWithJSON(name, tmpl, data)
if err != nil {
    if strings.Contains(err.Error(), "marshal param to JSON") {
        return nil, fmt.Errorf("template parameter not JSON-serializable: %w", err)
    }
    return nil, err
}

Prevention

When it happens

Trigger: Rendering a SQL/tool template with PopulateTemplate/PopulateTemplateWithJSON where the data map contains e.g. a channel, a function, or a cyclic nested value passed as a parameter.

Common situations: Passing a Go func or channel into template data by mistake; using map[customKey]any with non-basic key types; self-referencing structures built programmatically.

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 googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/75cbb9fe742814a8. Report an issue: GitHub.