nats-io/nats-server · error
using nats based account resolver - the system account needs
Error message
using nats based account resolver - the system account needs to be specified in configuration or the operator jwt
What it means
A NATS-based account resolver (DirAccResolver/CacheDirAccResolver, i.e. resolver: URL(...)) needs a system account to run its internal resolver traffic. This error is thrown when neither the config nor the first operator JWT specifies a system account while such a resolver is configured.
Source
Thrown at server/jwt.go:123
foundNonEmpty := false
for _, op := range o.TrustedOperators {
if op.SystemAccount != _EMPTY_ {
foundNonEmpty = true
}
if op.SystemAccount == o.SystemAccount {
foundSys = true
break
}
}
if foundNonEmpty && !foundSys {
return fmt.Errorf("system_account in config and operator JWT must be identical")
}
} else if o.TrustedOperators[0].SystemAccount == _EMPTY_ {
// In case the system account is neither defined in config nor in the first operator.
// If it would be needed due to the nats account resolver, raise an error.
switch o.AccountResolver.(type) {
case *DirAccResolver, *CacheDirAccResolver:
return fmt.Errorf("using nats based account resolver - the system account needs to be specified in configuration or the operator jwt")
}
}
srvMajor, srvMinor, srvUpdate, _ := versionComponents(VERSION)
for _, opc := range o.TrustedOperators {
if major, minor, update, err := jwt.ParseServerVersion(opc.AssertServerVersion); err != nil {
return fmt.Errorf("operator %s expects version %s got error instead: %s",
opc.Subject, opc.AssertServerVersion, err)
} else if major > srvMajor {
return fmt.Errorf("operator %s expected major version %d > server major version %d",
opc.Subject, major, srvMajor)
} else if srvMajor > major {
} else if minor > srvMinor {
return fmt.Errorf("operator %s expected minor version %d > server minor version %d",
opc.Subject, minor, srvMinor)
} else if srvMinor > minor {
} else if update > srvUpdate {
return fmt.Errorf("operator %s expected update version %d > server update version %d",View on GitHub (pinned to 3a66a489d2)
Solutions
- Add `system_account: AD...` to the config matching the operator's system account
- Or set one at operator level: `nsc edit operator --system-account AD...` and redeploy the operator JWT
Example fix
// before operator: eyJ... resolver: URL(nats://localhost:4222) // after operator: eyJ... resolver: URL(nats://localhost:4222) system_account: AD...
Defensive patterns
Strategy: validation
Validate before calling
// Go: NATS-based resolvers require a system account
switch o.AccountResolver.(type) {
case *DirAccResolver, *CacheDirAccResolver:
if o.SystemAccount == "" && o.TrustedOperators[0].SystemAccount == "" {
return fmt.Errorf("set system_account for URL resolver")
}
} Prevention
- Always create the operator with a system account (`nsc add operator --system-account`)
- Keep system_account in both resolver server and managed-server configs
- Check operator JWT contains a non-empty system_account before deploying URL resolvers
When it happens
Trigger: `resolver: URL(nats://...)` set, no `system_account` in config, and the first operator JWT has empty SystemAccount; validateOptions aborts startup.
Common situations: Standalone resolver-server setups where the operator was created without --system-account; minimal push/pull resolver configs missing the system_account line.
Related errors
- system_account in config and operator JWT must be identical
- account jwt not found
- auth callout violation: auth callout response is not for exp
- auth callout violation: auth callout response is not for ser
- auth callout signing key is unknown
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/d4b79a74a74c5c0e.
Report an issue: GitHub.