Netflix/chaosmonkey · error

failed to parse json at %s

Error message

failed to parse json at %s

What it means

Spinnaker.GetInstanceIDs throws this when json.Unmarshal fails to parse the response body into the expected {Name, Instances:[{Name}]} shape. The library wraps the unmarshal error with the URL, indicating the Spinnaker API returned something that is not the expected JSON structure.

Source

Thrown at spinnaker/spinnaker.go:284

	}()

	if resp.StatusCode != http.StatusOK {
		return "", nil, errors.Errorf("unexpected response code (%d) from %s", resp.StatusCode, url)
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", nil, errors.Wrap(err, fmt.Sprintf("body read failed at %s", url))
	}

	var data struct {
		Name      string
		Instances []struct{ Name string }
	}

	err = json.Unmarshal(body, &data)
	if err != nil {
		return "", nil, errors.Wrapf(err, "failed to parse json at %s", url)
	}

	asg := D.ASGName(data.Name)
	instances := make([]D.InstanceID, len(data.Instances))
	for i, instance := range data.Instances {
		instances[i] = D.InstanceID(instance.Name)
	}

	return asg, instances, nil

}

// GetApp implements deploy.Deployment.GetApp
func (s Spinnaker) GetApp(appName string) (*D.App, error) {
	// data arg is a map like {accountName: {clusterName: {regionName: {asgName: [instanceId]}}}}
	data := make(D.AppMap)
	for account, clusters := range s.clusters(appName) {
		cloudProvider, err := s.CloudProvider(account)

View on GitHub (pinned to eaa28fb761)

Solutions

  1. Log or print the raw body (temporarily) to see what the server actually returned.
  2. Verify the Spinnaker version matches the API schema this library expects; pin or update the library accordingly.
  3. Check whether an auth/login redirect is returning HTML instead of JSON.
  4. Curl the URL and validate the JSON matches {"name":..., "instances":[{"name":...}]}.
  5. Check for proxies or gateways mangling the response.

Example fix

// before
body, _ := ioutil.ReadAll(resp.Body)
var data struct{ Name string; Instances []struct{ Name string } }
err = json.Unmarshal(body, &data)
// after (diagnose first)
if err != nil {
    log.Printf("raw response from %s: %s", url, string(body))
}
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate that the endpoint speaks JSON
req, _ := http.NewRequest("GET", accountsProbeURL, nil)
req.Header.Set("Accept", "application/json")
resp, err := httpClient.Do(req)
if err != nil {
    return err
}
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "application/json") {
    return fmt.Errorf("spinnaker returned non-JSON content-type %q — check auth/proxy", ct)
}
resp.Body.Close()

Try / catch

// Go: log the body when parsing fails
asg, ids, err := sp.GetInstanceIDs(app, acct, cp, region, cluster)
if err != nil && strings.Contains(err.Error(), "failed to parse json") {
    log.Printf("spinnaker returned unexpected payload: %+v — check Spinnaker version and auth redirects", err)
}
return asg, ids, err

Prevention

When it happens

Trigger: Calling GetInstanceIDs when the endpoint returns HTML (error/login page), an empty body, truncated JSON, or a schema that changed between Spinnaker versions (e.g. field renames or a wrapped payload).

Common situations: Auth redirect returning a login page with 200; Spinnaker API version upgrade changing the payload; proxy injecting an error page; wrong URL pattern hitting a different endpoint that returns different JSON.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Netflix/chaosmonkey@eaa28fb761 (2026-09-03). Data as JSON: /api/errors/5dfc8df7fda6834e. Report an issue: GitHub.