nats-io/nats-server · error
operator %s expected update version %d > server update versi
Error message
operator %s expected update version %d > server update version %d
What it means
The final step of the version check: if the operator's asserted update (patch) version exceeds the running server's patch version (with major/minor equal), startup fails because the operator requires a newer patch release.
Source
Thrown at server/jwt.go:141
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",
opc.Subject, update, srvUpdate)
}
}
// If we have operators, fill in the trusted keys.
// FIXME(dlc) - We had TrustedKeys before TrustedOperators. The jwt.OperatorClaims
// has a DidSign(). Use that longer term. For now we can expand in place.
for _, opc := range o.TrustedOperators {
if o.TrustedKeys == nil {
o.TrustedKeys = make([]string, 0, 4)
}
if !opc.StrictSigningKeyUsage {
o.TrustedKeys = append(o.TrustedKeys, opc.Subject)
}
o.TrustedKeys = append(o.TrustedKeys, opc.SigningKeys...)
}
for _, key := range o.TrustedKeys {
if !nkeys.IsValidPublicOperatorKey(key) {
return fmt.Errorf("trusted Keys %q are required to be a valid public operator nkey", key)View on GitHub (pinned to 3a66a489d2)
Solutions
- Patch-upgrade nats-server to at least the asserted update version
- Or reissue the operator JWT with an assert <= the deployed server version
Example fix
// before server: 2.10.3, operator asserts 2.10.9 // after upgrade server to >= 2.10.9 # or reissue operator asserting 2.10.3
Defensive patterns
Strategy: validation
Validate before calling
// Go: compare asserted update version against running server
_, _, srvUpdate, _ := versionComponents(VERSION)
if _, _, update, err := jwt.ParseServerVersion(opc.AssertServerVersion); err == nil && update > srvUpdate {
return fmt.Errorf("server patch too old for operator (update %d > %d)", update, srvUpdate)
} Prevention
- Apply patch upgrades fleet-wide before re-asserting operators
- Automate a preflight that compares nats-server version to every operator's assert
- Avoid pinning servers to old patch releases in operator-mode clusters
When it happens
Trigger: Operator JWT asserts e.g. 2.10.9 while running nats-server 2.10.3; validateOptions update comparison fails.
Common situations: Security-reasserted operators after patch upgrades where only some hosts got the new server binary; conservative environments pinning old patch versions.
Related errors
- operator %s expected major version %d > server major version
- operator %s expected minor version %d > server minor version
- operators require an account resolver to be configured
- operators do not allow Accounts to be configured directly
- operators do not allow users to be configured directly
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/9ec33af4c61cc733.
Report an issue: GitHub.