Netflix/chaosmonkey · error
could not parse spinnaker apps list from %s: body: "%s": %v
Error message
could not parse spinnaker apps list from %s: body: "%s": %v
What it means
AppNames() unmarshals the response body into []spinnakerApp; if the body is not valid JSON or doesn't match the expected array shape, json.Unmarshal fails and the error is wrapped with the URL and the offending body text for inspection.
Source
Thrown at spinnaker/spinnaker.go:366
resp, err := s.client.Get(url)
if err != nil {
return nil, fmt.Errorf("could not retrieve list of apps from spinnaker url %s: %v", url, err)
}
defer func() {
if cerr := resp.Body.Close(); cerr != nil && err == nil {
err = fmt.Errorf("failed to close response body from %s: %v", url, err)
}
}()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read body when retrieving spinnaker app names from %s: %v", url, err)
}
var apps []spinnakerApp
err = json.Unmarshal(body, &apps)
if err != nil {
return nil, fmt.Errorf("could not parse spinnaker apps list from %s: body: \"%s\": %v", url, string(body), err)
}
result := make([]string, len(apps))
for i, app := range apps {
result[i] = app.Name
}
return result, nil
}
// spinnakerApp returns an app as represented by the Spinnaker API
type spinnakerApp struct {
Name string
}
// clusters returns a map from account name to list of cluster names
func (s Spinnaker) clusters(appName string) spinnakerClusters {View on GitHub (pinned to eaa28fb761)
Solutions
- Inspect the body text embedded in the error to see what was actually returned
- curl the apps URL with the client cert and confirm it returns a JSON array of apps
- Verify the endpoint URL includes the correct API path/version
- Check for proxies or auth redirects that could substitute HTML for the JSON payload
Defensive patterns
Strategy: validation
Validate before calling
// Validate the apps endpoint returns JSON before parsing:
resp, err := http.Get(appsURL)
if err != nil { return err }
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "application/json") {
return fmt.Errorf("apps endpoint returned non-JSON content type %q", ct)
} Try / catch
names, err := spin.AppNames()
if err != nil {
if strings.Contains(err.Error(), "could not parse spinnaker apps list") {
log.Printf("unexpected Spinnaker response; check URL/auth/proxies: %v", err)
return err
}
return err
} Prevention
- Verify the apps URL returns a JSON array with curl before deploying
- Check for proxies/LBs that substitute HTML (login/error pages)
- Confirm API path/version after Spinnaker upgrades
- Ensure auth failures aren't returning 200 with non-JSON bodies
When it happens
Trigger: Calling AppNames() when the Spinnaker apps endpoint returns a 200 response whose body fails json.Unmarshal into a JSON array of objects with a name field — e.g. HTML error pages, empty bodies, or a differently-shaped JSON object.
Common situations: A proxy/LB or login page returning HTML instead of the API response; wrong URL path hitting a non-API route; Spinnaker API version change altering the response shape; TLS-accepted-but-unauthorized responses returning non-JSON errors with 200.
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
- failed to parse json at %s
- json unmarshal failed
- 'attributes' field missing
- 'attributes.chaosMonkey' field missing
- 'attributes.chaosMonkey.enabled' field missing
AI-assisted analysis of Netflix/chaosmonkey@eaa28fb761 (2026-09-03).
Data as JSON: /api/errors/6fabba6adc785d0c.
Report an issue: GitHub.