Netflix/chaosmonkey · error

alternateAccountID called with forbidden arg: %s

Error message

alternateAccountID called with forbidden arg: %s

What it means

alternateAccountID() is a fallback for accounts without their own accountId: it maps names containing "test" to the "test" account and everything else to "prod". This guard rejects calls with "prod" or "test" themselves, because recursing on them would loop forever (AccountID("prod") -> no accountId -> alternateAccountID("prod") -> ...).

Source

Thrown at spinnaker/spinnaker.go:224

	}

	// Some backends may not have associated account ids
	if info.AccountID == "" {
		return s.alternateAccountID(name)
	}

	return info.AccountID, nil

}

// alternateAccountID returns an account ID for accounts that don't have their
// own ids.
func (s Spinnaker) alternateAccountID(name string) (string, error) {

	// Sanity check: this should never be called with "prod" or "test" as an
	// argument, since this would result in infinite recursion
	if name == "prod" || name == "test" {
		return "", fmt.Errorf("alternateAccountID called with forbidden arg: %s", name)
	}

	// Heuristic: if account name has "test" in the name, we return the "test"
	// account id, otherwise with  we use the "prod" account id
	if strings.Contains(name, "test") {
		return s.AccountID("test")
	}

	return s.AccountID("prod")
}

// Apps implements deploy.Deployment.Apps
func (s Spinnaker) Apps(c chan<- *D.App, appNames []string) {
	// Close the channel we're done
	defer close(c)

	for _, appName := range appNames {
		app, err := s.GetApp(appName)

View on GitHub (pinned to eaa28fb761)

Solutions

  1. Inspect the raw response of GET <endpoint>/accounts/prod — if accountId is genuinely missing, fix the Spinnaker/clouddriver deployment
  2. Check the API URL construction (accountURL) and the Spinnaker version compatibility; upgrade chaosmonkey or clouddriver as needed
  3. As a workaround, run against a Spinnaker instance that returns accountId for the prod/test accounts
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify prod/test accounts return an accountId before running:
var info struct{ AccountID string `json:"accountId"` }
// GET <endpoint>/accounts/prod, unmarshal; if AccountID == "", the fallback will trip

Try / catch

id, err := spin.AccountID("prod")
if err != nil {
	if strings.Contains(err.Error(), "alternateAccountID called with forbidden arg") {
		log.Printf("Spinnaker not returning accountId for prod/test: %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: AccountID("prod") or AccountID("test") succeeds at HTTP level but the response JSON has an empty accountId field, causing the fallback alternateAccountID("prod")/alternateAccountID("test") to be invoked, which immediately fails with this error.

Common situations: Spinnaker/clouddriver version change where the prod/test accounts stop returning an accountId field; a misbehaving backend returning 200 with empty bodies; querying an endpoint that proxies but does not enrich account data.

Understand the failure class

Related errors


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