googleapis/mcp-toolbox · error

could not unmarshal response as json: %w

Error message

could not unmarshal response as json: %w

What it means

parseResults successfully read the HTTP body but json.Unmarshal failed to decode it into a map[string]interface{}. The library expects every Cloud Healthcare API success response to be JSON; this error means the body was not valid JSON (or was JSON not shaped as an object, e.g. a bare array/string).

Source

Thrown at internal/sources/cloudhealthcare/cloud_healthcare.go:286

	_, ok := s.allowedDICOMStores[storeID]
	return ok
}

func (s *Source) UseClientAuthorization() bool {
	return s.UseClientOAuth
}

func parseResults(resp *http.Response) (any, error) {
	respBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("could not read response: %w", err)
	}
	if resp.StatusCode > 299 {
		return nil, fmt.Errorf("status %d %s: %s", resp.StatusCode, resp.Status, respBytes)
	}
	var jsonMap map[string]interface{}
	if err := json.Unmarshal(respBytes, &jsonMap); err != nil {
		return nil, fmt.Errorf("could not unmarshal response as json: %w", err)
	}
	return jsonMap, nil
}

func (s *Source) getService(tokenStr string) (*healthcare.Service, error) {
	svc := s.Service()
	var err error
	// Initialize new service if using user OAuth token
	if s.UseClientAuthorization() {
		svc, err = s.ServiceCreator()(tokenStr)
		if err != nil {
			return nil, fmt.Errorf("error creating service from OAuth access token: %w", err)
		}
	}
	return svc, nil
}

func isAlphanumeric(c byte) bool {

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Log the raw respBytes to see what non-JSON content is actually being returned
  2. Check for an intercepting proxy/CDN returning HTML — bypass it or add it to NO_PROXY
  3. If a DICOM/binary payload is expected, use the DICOM-specific tooling instead of the FHIR JSON path
  4. For NDJSON responses, switch to a decoder that reads a stream of objects (json.Decoder in a loop) instead of one Unmarshal

Example fix

// before
var jsonMap map[string]interface{}
if err := json.Unmarshal(respBytes, &jsonMap); err != nil {
    return nil, fmt.Errorf("could not unmarshal response as json: %w", err)
}
// after (handles ndjson streams too)
dec := json.NewDecoder(bytes.NewReader(respBytes))
var jsonMap map[string]interface{}
if err := dec.Decode(&jsonMap); err != nil {
    return nil, fmt.Errorf("could not unmarshal response as json (body: %.200s): %w", respBytes, err)
}
Defensive patterns

Strategy: type-guard

Validate before calling

function looksLikeJSON(s) { const t = s.trim(); return t.startsWith('{') || t.startsWith('['); }

Type guard

function isFHIRJSONObject(v) { return v !== null && typeof v === 'object' && !Array.isArray(v) && (v.resourceType !== undefined || v.total !== undefined); }

Try / catch

try {
  const result = await tool.invoke({ query });
  if (!isFHIRJSONObject(result)) throw new Error('Unexpected response shape: ' + JSON.stringify(result).slice(0, 200));
} catch (e) {
  if (/could not unmarshal response as json/.test(e.message)) {
    // inspect raw body in the message; check for proxy/HTML interception
  }
  throw e;
}

Prevention

When it happens

Trigger: GetFHIRResource, FHIRPatientSearch, FHIRPatientEverything or FHIRFetchPage receive a 2xx response whose body is HTML (proxy/login page), empty, truncated, or a JSON array/other non-object type, so json.Unmarshal into map[string]interface{} errors.

Common situations: A corporate proxy or load balancer intercepting the request and returning an HTML error page with 200; a misconfigured binary/DICOM response being read through the FHIR path; Google returning an NDJSON stream (search-with-post returning concatenated JSON) that is not a single object.

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