Netflix/chaosmonkey · error

unexpected response code (%d) from %s

Error message

unexpected response code (%d) from %s

What it means

Spinnaker.GetInstanceIDs throws this when the Spinnaker API responds with any HTTP status other than 200 OK for the active-ASG lookup. The library treats only 200 as success and includes the actual status code and URL in the message so the caller can diagnose whether the cluster, account, region, or provider inputs were wrong or the service is unhappy.

Source

Thrown at spinnaker/spinnaker.go:269

}

// GetInstanceIDs gets the instance ids for a cluster
func (s Spinnaker) GetInstanceIDs(app string, account D.AccountName, cloudProvider string, region D.RegionName, cluster D.ClusterName) (D.ASGName, []D.InstanceID, error) {
	url := s.activeASGURL(app, string(account), string(cluster), cloudProvider, string(region))

	resp, err := s.client.Get(url)
	if err != nil {
		return "", nil, errors.Wrapf(err, "http get failed at %s", url)
	}

	defer func() {
		if cerr := resp.Body.Close(); cerr != nil && err == nil {
			err = errors.Wrapf(err, "body close failed at %s", url)
		}
	}()

	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)

View on GitHub (pinned to eaa28fb761)

Solutions

  1. Read the status code from the error message; if 404, verify the app/account/cluster/region names exist in Spinnaker.
  2. If 401/403, refresh credentials or check the client's auth configuration.
  3. If 5xx, check Spinnaker gate/echo health and retry after the service recovers.
  4. Curl the URL manually to compare the raw response with your inputs.
  5. Regenerate the URL inputs (cluster naming conventions may have changed).

Example fix

// before
_, ids, err := sp.GetInstanceIDs("myapp", "prod", "aws", "us-east-1", "myapp-prod")
// after
// verify cluster exists first, then call
clusters, _ := sp.GetClusterNames("myapp", "prod")
if contains(clusters, "myapp-prod") {
    _, ids, err = sp.GetInstanceIDs("myapp", "prod", "aws", "us-east-1", "myapp-prod")
}
Defensive patterns

Strategy: validation

Validate before calling

// verify the cluster/account/region inputs exist before the call
clusters, err := sp.GetClusterNames(app, account)
if err != nil {
    return err
}
found := false
for _, c := range clusters {
    if c == cluster {
        found = true
        break
    }
}
if !found {
    return fmt.Errorf("cluster %q not found for app %q / account %q", cluster, app, account)
}

Try / catch

// Go: branch on status code parsed from the message or re-check inputs
_, _, err := sp.GetInstanceIDs(app, acct, cp, region, cluster)
if err != nil {
    var sErr interface{ Error() string }
    if errors.As(err, &sErr) && strings.Contains(err.Error(), "unexpected response code (4") {
        // 4xx: fix inputs/credentials, do not retry
        return fmt.Errorf("bad request to spinnaker: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling GetInstanceIDs with an app/account/cluster/region combination that does not exist (404), with bad credentials (401/403), when the Spinnaker server is overloaded (5xx), or when activeASGURL builds a path the API does not recognize.

Common situations: Typo or stale cluster/account name after infrastructure changes; app was deleted or renamed; Spinnaker gate returning 502/503 behind a proxy; auth token expired; API version change moved the endpoint.

Related errors


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