googleapis/mcp-toolbox · error

error marshlling json: %v

Error message

error marshlling json: %v

What it means

postDqlQuery marshals the query payload ({Query, Variables}) to JSON before building the HTTP request. This error means json.Marshal failed on that payload. Since it contains a string query and a map of variables, failure typically indicates the params map holds values that cannot be JSON-serialized (e.g. channels, funcs, or cyclic structures).

Source

Thrown at internal/sources/dgraph/dgraph.go:200

// postDqlQuery sends a DQL query to the Dgraph server with query, parameters, and optional timeout.
// Returns the response body ([]byte) and an error, if any.
func (hc *DgraphClient) postDqlQuery(query string, paramsMap map[string]interface{}, timeout string) ([]byte, error) {
	urlParams := url.Values{}
	urlParams.Add("timeout", timeout)
	url, err := getUrl(hc.baseUrl, "/query", urlParams)
	if err != nil {
		return nil, err
	}
	p := struct {
		Query     string                 `json:"query"`
		Variables map[string]interface{} `json:"variables"`
	}{
		Query:     query,
		Variables: paramsMap,
	}
	body, err := json.Marshal(p)
	if err != nil {
		return nil, fmt.Errorf("error marshlling json: %v", err)
	}

	req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(body))
	if err != nil {
		return nil, fmt.Errorf("error building req for endpoint [%v] :%v", url, err)
	}

	req.Header.Add("Content-Type", "application/json")

	return hc.doReq(req)
}

// mutate sends an RDF mutation to the Dgraph server with "commitNow: true", embedding parameters.
// Returns the server's response as a byte slice or an error if the mutation fails.
func (hc *DgraphClient) mutate(mutation string, paramsMap map[string]interface{}) ([]byte, error) {
	mu := embedParamsIntoMutation(mutation, paramsMap)
	params := url.Values{}
	params.Add("commitNow", "true")

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Ensure all query parameters are JSON-serializable primitives (string, number, bool, arrays, objects)
  2. Sanitize/convert parameter values to map[string]any of primitives before calling ExecuteQuery
  3. Log the paramsMap contents to identify the offending value
  4. Check how the tool converts incoming parameters into paramsMap for a type-conversion bug

Example fix

// before
params := map[string]any{"cb": func() {}} // not serializable
body, err := json.Marshal(p) // fails
// after
params := map[string]any{"name": "alice", "limit": 10} // primitives only
body, err := json.Marshal(p)
Defensive patterns

Strategy: validation

Validate before calling

for k, v := range paramsMap {
	if !isJSONSerializable(v) {
		return fmt.Errorf("parameter %q of type %T is not JSON-serializable", k, v)
	}
}

func isJSONSerializable(v any) bool {
	_, err := json.Marshal(v)
	return err == nil
}

Try / catch

data, err := svc.ExecuteQuery(ctx, query, params)
if err != nil && strings.Contains(err.Error(), "marshlling json") {
	// sanitize params to primitives and retry
}

Prevention

When it happens

Trigger: Calling ExecuteQuery with parameters whose JSON conversion fails — e.g. a paramsMap containing unsupported types after conversion from the incoming parameter map.

Common situations: Passing non-JSON-serializable values (time.Time is fine, but custom structs with unexported fields producing empty maps are not; funcs/channels panic-adjacent) through tool parameters; nil maps are fine but exotic values are not.

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/29c7df9be84b57d7. Report an issue: GitHub.