nats-io/nats-server · error
operators do not allow authorization callouts to be configur
Error message
operators do not allow authorization callouts to be configured directly
What it means
When operator mode is in effect (trusted operators / JWT-based auth), all authorization must be managed via account-scoped authorization callouts declared in operator/account JWTs, not via the server's own configuration. If `authorization {}` (AuthCallout) is set directly in server config while operator mode is enabled, `validateTrustedOperators` in server/jwt.go:176 rejects the configuration at startup.
Source
Thrown at server/jwt.go:176
if !nkeys.IsValidPublicOperatorKey(key) {
return fmt.Errorf("trusted Keys %q are required to be a valid public operator nkey", key)
}
}
if len(o.resolverPinnedAccounts) > 0 {
for key := range o.resolverPinnedAccounts {
if !nkeys.IsValidPublicAccountKey(key) {
return fmt.Errorf("pinned account key %q is not a valid public account nkey", key)
}
}
// ensure the system account (belonging to the operator can always connect)
if o.SystemAccount != _EMPTY_ {
o.resolverPinnedAccounts[o.SystemAccount] = struct{}{}
}
}
// If we have an auth callout defined make sure we are not in operator mode.
if o.AuthCallout != nil {
return errors.New("operators do not allow authorization callouts to be configured directly")
}
return nil
}
func validateSrc(claims *jwt.UserClaims, host string) bool {
if claims == nil {
return false
} else if len(claims.Src) == 0 {
return true
} else if host == "" {
return false
}
ip := net.ParseIP(host)
if ip == nil {
return false
}
for _, cidr := range claims.Src {View on GitHub (pinned to 3a66a489d2)
Solutions
- Remove the `authorization { ... }` callout block from the server config and define the auth callout in an account JWT instead (pushed via resolver or embedded)
- If direct auth callout is intended, remove the trusted operator/operator mode configuration
- Move any user-level auth into account/user JWTs managed by the operator's signing key
Example fix
// before: operator mode + direct callout in nats-server.conf
resolver: URL(...)
authorization {
users = [ ... ]
}
// after: authorization via account JWT only
resolver: URL(...)
// (authorization block removed; callout configured in the account JWT) Defensive patterns
Strategy: validation
Validate before calling
// Reject the config combination before startup
if hasTrustedOperators(cfg) && cfg.Authorization != nil {
return errors.New("auth callout cannot be configured directly in operator mode")
} Prevention
- Keep a dedicated operator-mode config without authorization blocks
- Define auth callouts in account JWTs, never in server config
- Audit configs with nats-server --config check or a linter before deploy
When it happens
Trigger: Starting a server with both a resolver/operator JWT setup (trusted operators) and a direct `authorization { ... }` block in the config file; enabling operator mode via `--trusted` while auth callout options remain present.
Common situations: Migrating a self-managed server to operator mode and forgetting to remove the legacy auth callout block; copying a config from a non-operator deployment into an operator-mode deployment; enabling trusted operators in a test config that still has auth callout settings.
Related errors
- error non operator mode account %q: attempted to use issuer_
- account %q not permitted as valid account option for auth ca
- account jwt not found
- authorization response had validation errors: %v
- wrong issuer for auth callout response on account %q, expect
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/bf086c90b4b208f0.
Report an issue: GitHub.