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

  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.