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

  1. Add `system_account: AD...` to the config matching the operator's system account
  2. 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

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


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