Netflix/chaosmonkey · error
json unmarshal failed, body: %s
Error message
json unmarshal failed, body: %s
What it means
OtherID throws this when json.Unmarshal cannot decode the instance endpoint response into the expected struct with Health and Error fields. The request completed and the body was read, but the body is not the expected JSON document. The failing body is embedded verbatim in the message so you can see exactly what Spinnaker returned.
Source
Thrown at spinnaker/terminator.go:187
"state": "Up"
},
{
"instanceId": "55fe33ab-5b66-450a-85f7-f3129806b87f",
"titusTaskId": "Titus-123456-worker-0-0",
...
}
],
}
*/
var fields struct {
Health []map[string]interface{} `json:"health"`
Error string `json:"error"`
}
err = json.Unmarshal(body, &fields)
if err != nil {
return "", errors.Wrap(err, fmt.Sprintf("json unmarshal failed, body: %s", body))
}
if resp.StatusCode != http.StatusOK {
if fields.Error == "" {
return "", fmt.Errorf("unexpected status code: %d. body: %s", resp.StatusCode, body)
}
return "", fmt.Errorf("unexpected status code: %d. error: %s", resp.StatusCode, fields.Error)
}
// In some cases, an instance may be missing health information.
// We just return a blank otherID in that case
if len(fields.Health) < 2 {
return "", nil
}
otherID, ok := fields.Health[1]["instanceId"].(string)
if !ok {View on GitHub (pinned to eaa28fb761)
Solutions
- Inspect the body embedded in the error message to see what was actually returned.
- Curl the same URL with the same credentials to reproduce and inspect headers (content-type, content-encoding).
- Check whether the instance still exists in Spinnaker/Titus; a terminated instance may yield a non-JSON error page.
- Verify no auth/SSO proxy is intercepting the request and that the endpoint URL targets Gate's instance API.
- Confirm your Spinnaker version's instance response matches the library's expected schema and update the library or Spinnaker accordingly.
Defensive patterns
Strategy: validation
Validate before calling
resp, err := client.Get(instanceURL)
if err != nil {
return err
}
body, _ := ioutil.ReadAll(resp.Body)
if !json.Valid(body) {
return fmt.Errorf("non-JSON from %s (content-type: %s): %.200s", instanceURL, resp.Header.Get("Content-Type"), body)
}
var probe struct{ Health []json.RawMessage }
if err := json.Unmarshal(body, &probe); err != nil {
return fmt.Errorf("unexpected instance schema: %v", err)
} Type guard
func looksLikeInstanceDoc(body []byte) bool {
var probe struct{ Health []map[string]interface{} }
return json.Unmarshal(body, &probe) == nil
} Try / catch
err = json.Unmarshal(body, &fields)
if err != nil {
log.Printf("json unmarshal failed for %s, body: %.500s", url, body)
return "", errors.Wrap(err, fmt.Sprintf("json unmarshal failed, body: %s", body))
} Prevention
- Check the instance still exists in Spinnaker before querying; terminated instances return unexpected documents
- Verify content-encoding handling (gzip) matches between client and Gate
- Ensure no auth/SSO proxy intercepts instance GETs with HTML responses
- Log a truncated body snippet on unmarshal failure for fast diagnosis
When it happens
Trigger: GET <spinnaker-api>/<account>/<region>/<instanceId> returns a body that is not valid JSON for the expected schema: an HTML error/login page from a proxy, an empty body, gzip/encoding garbage, or a Spinnaker response whose instance payload differs from the expected {health: [...]} shape.
Common situations: Instance already terminated so Gate returns an unexpected document; an SSO/auth proxy intercepting the GET with its own HTML response; content-encoding mismatches (client not handling gzip); Spinnaker version changes altering the instance response schema; wrong endpoint URL hitting a non-Gate service.
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
- 'attributes' field missing
- 'attributes.chaosMonkey' field missing
- 'attributes.chaosMonkey.enabled' field missing
- attributes.chaosMonkey.meanTimeBetweenKillsInWorkDays missin
- attributes.chaosMonkey.minTimeBetweenKillsInWorkDays missing
AI-assisted analysis of Netflix/chaosmonkey@eaa28fb761 (2026-09-03).
Data as JSON: /api/errors/3b1b30baf659556e.
Report an issue: GitHub.