Netflix/chaosmonkey · error

unexpected response code: %d, body: %s

Error message

unexpected response code: %d, body: %s

What it means

Returned by Terminator.Execute when Spinnaker responds to the termination POST with a status other than 200; the body of the non-OK response is read and included to show why Spinnaker rejected the terminate request.

Source

Thrown at spinnaker/terminator.go:99

	payload := killJSONPayload(ins, otherID, s.user)
	resp, err := s.client.Post(url, "application/json", bytes.NewReader(payload))
	if err != nil {
		return errors.Wrap(err, fmt.Sprintf("POST to %s failed, (body '%s')", url, string(payload)))
	}

	defer func() {
		if cerr := resp.Body.Close(); cerr != nil && err == nil {
			err = errors.Wrap(cerr, fmt.Sprintf("failed to close response body of %s", url))
		}
	}()

	if resp.StatusCode != http.StatusOK {
		log.Printf("Unexpected response: %d", resp.StatusCode)
		contents, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return errors.Wrap(err, "failed to read response body")
		}
		return fmt.Errorf("unexpected response code: %d, body: %s", resp.StatusCode, string(contents))
	}

	return nil
}

// killJsonPayload generates the JSON request body for terminating an instance
// otherID is an optional second instance ID, as some backends may have a second
// identifer.
func killJSONPayload(ins chaosmonkey.Instance, otherID string, spinnakerUser string) []byte {
	var desc string
	if otherID != "" {
		desc = fmt.Sprintf("Chaos Monkey terminate instance: %s %s (%s, %s, %s)", ins.ID(), otherID, ins.AccountName(), ins.RegionName(), ins.ASGName())
	} else {
		desc = fmt.Sprintf("Chaos Monkey terminate instance: %s (%s, %s, %s)", ins.ID(), ins.AccountName(), ins.RegionName(), ins.ASGName())
	}

	p := killPayload{
		Application: ins.AppName(),

View on GitHub (pinned to eaa28fb761)

Solutions

  1. Log/inspect the returned body to see Spinnaker's error detail
  2. Verify Spinnaker API URL and authentication credentials
  3. Check that the instance ID/account/region in the kill payload is valid
  4. Check Spinnaker server health if 5xx persists

Example fix

// before
return fmt.Errorf("unexpected response code: %d, body: %s", resp.StatusCode, string(contents))
// after
if resp.StatusCode == http.StatusUnauthorized {
    return fmt.Errorf("spinnaker auth failed (401), refresh credentials")
}
return fmt.Errorf("unexpected response code: %d, body: %s", resp.StatusCode, string(contents))
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: check Spinnaker reachability and auth
resp, err := http.Get(spinURL + "/health")
if err != nil || resp.StatusCode != http.StatusOK {
    return fmt.Errorf("spinnaker unreachable or unhealthy")
}

Try / catch

err := terminator.Execute(instance)
if err != nil {
    if strings.Contains(err.Error(), "401") || strings.Contains(err.Error(), "403") {
        // refresh credentials and retry once
    } else if strings.Contains(err.Error(), "unexpected response code: 5") {
        // retry with backoff
    }
}

Prevention

When it happens

Trigger: Calling spinnaker.Terminator.Execute (kill) when the Spinnaker API returns 4xx (bad auth, bad payload) or 5xx (server error).

Common situations: Expired Spinnaker auth token, malformed instance ID, Spinnaker/Gate down or overloaded, wrong endpoint URL.

Related errors


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