nats-io/nats-server · error
default sentinel requires operators and accounts
Error message
default sentinel requires operators and accounts
What it means
validateTrustedOperators in server/jwt.go enforces that the DefaultSentinel option (a user JWT used as a default account placeholder) can only be configured when trusted operators are also configured. If TrustedOperators is empty but DefaultSentinel is set, startup validation fails with 'default sentinel requires operators and accounts'.
Source
Thrown at server/jwt.go:74
}
return theJWT, opc, nil
}
// Just wipe slice with 'x', for clearing contents of nkey seed file.
func wipeSlice(buf []byte) {
for i := range buf {
buf[i] = 'x'
}
}
// validateTrustedOperators will check that we do not have conflicts with
// assigned trusted keys and trusted operators. If operators are defined we
// will expand the trusted keys in options.
func validateTrustedOperators(o *Options) error {
if len(o.TrustedOperators) == 0 {
// if we have no operator, default sentinel shouldn't be set
if o.DefaultSentinel != _EMPTY_ {
return fmt.Errorf("default sentinel requires operators and accounts")
}
return nil
}
if o.DefaultSentinel != _EMPTY_ {
juc, err := jwt.DecodeUserClaims(o.DefaultSentinel)
if err != nil {
return fmt.Errorf("default sentinel JWT not valid")
}
if !juc.BearerToken && juc.IssuerAccount != "" && juc.HasEmptyPermissions() {
// we cannot resolve the account yet - but this looks like a scoped user
// it will be rejected at runtime if not valid
} else if !juc.BearerToken {
return fmt.Errorf("default sentinel must be a bearer token")
}
}
if o.AccountResolver == nil {
return fmt.Errorf("operators require an account resolver to be configured")View on GitHub (pinned to 3a66a489d2)
Solutions
- Remove the default_sentinel setting from nats.conf if operator mode is not used.
- Configure operators instead: set `operator` JWT and an account resolver (and move accounts into JWTs).
- Restart and confirm `nats server info` shows the trusted keys/operators loaded.
Example fix
// before (nats.conf)
default_sentinel: "eyJ..."
// after: either remove the line, or add operator setup
operator: "eyJ..."
resolver: MEMORY
resolver_preload: { ACC: "eyJ..." }
default_sentinel: "eyJ..." Defensive patterns
Strategy: validation
Validate before calling
# before starting the server if grep -q '^default_sentinel:' nats.conf && ! grep -q '^operator:' nats.conf; then echo "default_sentinel requires operator mode"; exit 1 fi
Prevention
- Only set default_sentinel in operator-mode deployments.
- Validate config with `nats-server -t` (config test) before restart.
- Template configs per deployment mode so sentinel is not copied into non-operator setups.
- Document default_sentinel's dependency on TrustedOperators in runbooks.
When it happens
Trigger: Starting nats-server with `default_sentinel` set in config (or Options.DefaultSentinel set programmatically) without `operator`/`resolver` based trusted operators configured, i.e. in a non-operator mode server.
Common situations: Copying a config file from an operator-mode deployment into a plain single-account/dev server; enabling default sentinel for auth without adopting the operator/JWT setup.
Related errors
- default sentinel JWT not valid
- default sentinel must be a bearer token
- operators do not allow authorization callouts to be configur
- mqtt authentication token not compatible with presence of us
- no operator key found
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/a3037885247b739a.
Report an issue: GitHub.