googleapis/mcp-toolbox · error

failed to unmarshal json

Error message

failed to unmarshal json: %w, body: %s

What it means

After a 200 response, RunQuery unmarshals the body into map[string]any. If the body is not valid JSON (or empty-but-nonzero garbage, HTML error pages from proxies, or truncated data), the unmarshal error plus the raw body are wrapped in this error.

Solutions

  1. Inspect the body snippet in the error to identify what was actually returned
  2. Verify no proxy/intermediary is substituting HTML responses for API JSON
  3. Ensure the HTTP transport handles gzip/deflate correctly
  4. Retry; if persistent, log the full response headers and escalate to the network owner

Example fix

// before
// response is gzip-compressed, json.Unmarshal fails
client := &http.Client{}
// after
transport := &http.Transport{DisableCompression: false}
client := &http.Client{Transport: transport} // Go auto-decompresses gzip
Defensive patterns

Strategy: type-guard

Validate before calling

resp, err := http.Get(url)
if err == nil {
    ct := resp.Header.Get("Content-Type")
    if !strings.Contains(ct, "application/json") {
        return fmt.Errorf("unexpected content-type %q; proxy may be intercepting", ct)
    }
}

Try / catch

result, err := src.RunQuery(ctx, query)
if err != nil {
    if strings.Contains(err.Error(), "failed to unmarshal json") {
        log.Printf("non-JSON body returned (proxy/CDN issue?): %.200s", err)
        return fmt.Errorf("monitoring API returned invalid JSON; check proxies")
    }
    return err
}

Prevention

When it happens

Trigger: A successful (200) Cloud Monitoring response whose body fails json.Unmarshal — typically HTML/HTML-encoded proxy error pages, gzip content not decoded (missing Accept-Encoding handling), or truncated JSON.

Common situations: Corporate proxies injecting HTML login pages; misconfigured transports that don't decompress gzip responses; intermediary caching layers corrupting bodies.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at internal/sources/cloudmonitoring/cloud_monitoring.go:176

	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response body: %w", err)
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("request failed: %s, body: %s", resp.Status, string(body))
	}

	if len(body) == 0 {
		return nil, nil
	}

	var result map[string]any
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, fmt.Errorf("failed to unmarshal json: %w, body: %s", err, string(body))
	}

	return result, nil
}

View on GitHub (pinned to 8cc6e09de2)