nats-io/nats-server · error

operators require an account resolver to be configured

Error message

operators require an account resolver to be configured

What it means

This error is thrown by validateTrustedOperators in server/jwt.go when operator-mode (TrustedOperators) is configured but no AccountResolver is set. Operator mode relies on decentralized JWT authentication, so the server needs a resolver (memory, directory, or NATS-based) to look up account signing keys and account JWTs. Without it, operator mode cannot function, so server startup is aborted.

Source

Thrown at server/jwt.go:92

			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")
	}
	if len(o.Accounts) > 0 {
		return fmt.Errorf("operators do not allow Accounts to be configured directly")
	}
	if len(o.Users) > 0 || len(o.Nkeys) > 0 {
		return fmt.Errorf("operators do not allow users to be configured directly")
	}
	if len(o.TrustedOperators) > 0 && len(o.TrustedKeys) > 0 {
		return fmt.Errorf("conflicting options for 'TrustedKeys' and 'TrustedOperators'")
	}
	if o.SystemAccount != _EMPTY_ {
		foundSys := false
		foundNonEmpty := false
		for _, op := range o.TrustedOperators {
			if op.SystemAccount != _EMPTY_ {
				foundNonEmpty = true
			}
			if op.SystemAccount == o.SystemAccount {

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Add a resolver to the config, e.g. `resolver: MEMORY` with `include accounts/` directives, or `resolver: URL(nats://resolver-host:4222)` for a NATS-based resolver
  2. If you only need static accounts, drop the operator setting and configure accounts/users directly instead of operator mode
  3. Verify with `nats-server -c nats.conf -t` (config test) before deploying

Example fix

// before
operator: eyJhbGciOi... 
// after
operator: eyJhbGciOi...
resolver: MEMORY
resolver_preload: {
  AD...: eyJhbGciOi...
}
Defensive patterns

Strategy: validation

Validate before calling

// Go: check options before ProcessOptions/ValidateOptions
if len(o.TrustedOperators) > 0 && o.AccountResolver == nil {
    return fmt.Errorf("config sets operators but no resolver")
}

Prevention

When it happens

Trigger: Config file sets an 'operator' (TrustedOperators) but omits any 'resolver' setting; validateOptions fails before the server starts.

Common situations: Minimal operator-mode configs copied from docs that show the operator JWT but forget the resolver: e.g. `operator: <jwt>` with no `resolver: MEMORY` or `resolver: URL(...)` line; also when switching from plain account config to operator mode and deleting the resolver block.

Related errors


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