nats-io/nats-server · error

not allowed to delete system account

Error message

not allowed to delete system account

What it means

The resolver explicitly refuses to delete the system account (acc == sysAccName) and returns 'not allowed to delete system account'. This is a deliberate safety guard protecting the SYS account that nats-server relies on for internal messaging/monitoring.

Source

Thrown at server/accounts.go:4385

		subj = gk.Subject
		if store.deleteType == NoDelete {
			err = fmt.Errorf("delete must be enabled in server config")
		} else if subj != gk.Issuer {
			err = fmt.Errorf("not self signed")
		} else if _, ok := store.operator[gk.Issuer]; !ok {
			err = fmt.Errorf("not trusted")
		} else if list, ok := gk.Data["accounts"]; !ok {
			err = fmt.Errorf("malformed request")
		} else if accIds, ok = list.([]any); !ok {
			err = fmt.Errorf("malformed request")
		} else {
			for _, entry := range accIds {
				if acc, ok := entry.(string); !ok ||
					acc == _EMPTY_ || !nkeys.IsValidPublicAccountKey(acc) {
					err = fmt.Errorf("malformed request")
					break
				} else if acc == sysAccName {
					err = fmt.Errorf("not allowed to delete system account")
					break
				}
			}
		}
	}
	if err != nil {
		respondToUpdate(s, reply, _EMPTY_, fmt.Sprintf("delete accounts request by %s failed", subj), err)
		return
	}
	errs := []string{}
	passCnt := 0
	for _, acc := range accIds {
		if err := store.delete(acc.(string)); err != nil {
			errs = append(errs, err.Error())
		} else {
			passCnt++
		}
	}

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Remove the system account public key from the claim's accounts list before publishing.
  2. Filter out the key returned by the server's system_account config in your automation.
  3. If SYS must be replaced, provision a new resolver/operator setup rather than deleting SYS.

Example fix

// before
accounts := allAccounts // includes system account key
// after
accounts := slices.DeleteFunc(allAccounts, func(a string) bool { return a == sysAccountPubKey })
Defensive patterns

Strategy: validation

Validate before calling

sysKey := serverSystemAccountPubKey // from server config
for _, a := range accounts {
    if a == sysKey {
        return fmt.Errorf("refusing to delete system account %s", a)
    }
}

Try / catch

if err := pushClaim(jwt); err != nil && strings.Contains(err.Error(), "not allowed to delete system account") {
    log.Fatalf("remove SYS account key from delete list; it is protected")
}

Prevention

When it happens

Trigger: Submitting a delete operator claim whose accounts list includes the system account's public key (the key matching the server's system account, e.g. from system_account config).

Common situations: Bulk cleanup scripts that 'delete all accounts' including SYS; operators trying to remove a compromised environment wholesale; scripts copying the full account list from the resolver without excluding SYS.

Related errors


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/e3af2c5fba497823. Report an issue: GitHub.