nats-io/nats-server · error

operator %s expected minor version %d > server minor version

Error message

operator %s expected minor version %d > server minor version %d

What it means

Similar to the major check: the operator asserts a minimum minor version. If the operator's minor version exceeds the running server's (with major equal), the server refuses to start since required features may be missing.

Source

Thrown at server/jwt.go:137

		// 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",
				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...)

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Upgrade nats-server to at least the asserted minor version
  2. Or lower the operator's assert with `nsc edit operator ...` / reissue the JWT

Example fix

// before
server: 2.10.11, operator asserts 2.11.0
// after
upgrade server to >= 2.11.0  # or reissue operator asserting 2.10.0
Defensive patterns

Strategy: validation

Validate before calling

// Go: compare asserted minor against running server before startup
_, srvMinor, _, _ := versionComponents(VERSION)
if _, minor, _, err := jwt.ParseServerVersion(opc.AssertServerVersion); err == nil && minor > srvMinor {
    return fmt.Errorf("server too old for operator (minor %d > %d)", minor, srvMinor)
}

Prevention

When it happens

Trigger: Operator JWT asserts e.g. 2.11.0 while running nats-server 2.10.x; validateOptions minor comparison fails.

Common situations: Operator updated with newer nsc (asserting latest features) but the server cluster not yet upgraded; mixed-version fleets where one config is pushed everywhere.

Related errors


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