googleapis/mcp-toolbox · error
failed to unmarshal json: %w, body: %s
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.
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)
Solutions
- Inspect the body snippet in the error to identify what was actually returned
- Verify no proxy/intermediary is substituting HTML responses for API JSON
- Ensure the HTTP transport handles gzip/deflate correctly
- 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
- Ensure HTTP transports auto-decompress gzip
- Bypass auth portals/captive proxies for googleapis.com
- Log Content-Type headers when debugging
- Pin DNS/hosts to avoid intercepted endpoints
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
- failed to read response body: %w
- request failed: %s, body: %s
- error parsing JSON: %v
- failed to marshal payload: %w
- Failed to encode PRM response
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/6efd524c3b382f2e.
Report an issue: GitHub.