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

  1. Patch-upgrade nats-server to at least the asserted update version
  2. 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

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


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