Netflix/chaosmonkey · error
json unmarshal failed
Error message
json unmarshal failed
What it means
fromJSON unmarshals the raw Spinnaker response into an internal parsedJSON structure. If json.Unmarshal fails, the error is wrapped as 'json unmarshal failed'. The response was readable HTTP 200 but its JSON shape/types do not match the expected struct.
Source
Thrown at spinnaker/fromjson.go:98
// "stack": "foo",
// "detail": "bar"
// }
// ],
// "whitelist": [
// {
// "account": "test",
// "stack": "*",
// "region": "*",
// "detail": "*"
// }
// ]
// }
func fromJSON(js []byte) (*chaosmonkey.AppConfig, error) {
parsed := new(parsedJSON)
err := json.Unmarshal(js, parsed)
if err != nil {
return nil, errors.Wrap(err, "json unmarshal failed")
}
if parsed.Attributes == nil {
return nil, errors.New("'attributes' field missing")
}
if parsed.Attributes.ChaosMonkey == nil {
return nil, errors.New("'attributes.chaosMonkey' field missing")
}
cm := parsed.Attributes.ChaosMonkey
if cm.Enabled == nil {
return nil, errors.New("'attributes.chaosMonkey.enabled' field missing")
}
// Check if mean time between kills is missing.
// If not enabled, it's ok if it's missingView on GitHub (pinned to eaa28fb761)
Solutions
- Log/dump the raw response body (or its first bytes) to see what was actually received
- Confirm the endpoint returns the expected Spinnaker application JSON (compare against a curl of the gate URL)
- Check for proxies/auth layers returning HTML with 200 status
- Verify the Spinnaker API version is compatible with this library's parsedJSON schema
- Add a content-type check before unmarshaling
Example fix
// caller-side guard before trusting Get output
body, _ := ioutil.ReadAll(resp.Body)
if !json.Valid(body) {
log.Printf("non-JSON response from gate: %.200s", body)
return errors.New("gate returned invalid JSON")
} Defensive patterns
Strategy: validation
Validate before calling
body, err := ioutil.ReadAll(resp.Body)
if err != nil { return err }
if len(bytes.TrimSpace(body)) == 0 {
return errors.New("empty response body from gate")
}
if !json.Valid(body) {
return fmt.Errorf("non-JSON response from gate: %.200s", body)
} Type guard
func looksLikeGateJSON(body []byte) bool {
if !json.Valid(body) { return false }
var probe struct {
Attributes map[string]interface{} `json:"attributes"`
}
return json.Unmarshal(body, &probe) == nil && probe.Attributes != nil
} Try / catch
cfg, err := getter.Get(app)
if err != nil && strings.Contains(err.Error(), "json unmarshal failed") {
log.Printf("gate returned malformed JSON for %s; check proxies/API version: %+v", app, err)
return err
} Prevention
- Pin and test against the Spinnaker API version this library expects
- Reject HTML error pages early by checking Content-Type and json.Valid
- Log a bounded snippet of the raw body when unmarshal fails
- Watch for Spinnaker upgrades that change the applications response schema
When it happens
Trigger: json.Unmarshal(js, parsed) returns an error: response is empty, HTML (e.g. an error page from a proxy), truncated JSON, or field types differing from parsedJSON expectations (e.g. a string where a number is expected).
Common situations: A reverse proxy or login page returning HTML with status 200; Spinnaker API version changes altering the response schema; interrupted responses producing truncated JSON; empty body from gate on odd conditions.
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/2102e7bb26129b34.
Report an issue: GitHub.