{"record":{"id":"ec33fece19a27705","repo":"nats-io/nats-server","slug":"operator-s-expects-version-s-got-error-instead","errorCode":null,"errorMessage":"operator %s expects version %s got error instead: %s","messagePattern":"operator (.+?) expects version (.+?) got error instead: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/jwt.go","lineNumber":130,"sourceCode":"\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif foundNonEmpty && !foundSys {\n\t\t\treturn fmt.Errorf(\"system_account in config and operator JWT must be identical\")\n\t\t}\n\t} else if o.TrustedOperators[0].SystemAccount == _EMPTY_ {\n\t\t// In case the system account is neither defined in config nor in the first operator.\n\t\t// If it would be needed due to the nats account resolver, raise an error.\n\t\tswitch o.AccountResolver.(type) {\n\t\tcase *DirAccResolver, *CacheDirAccResolver:\n\t\t\treturn fmt.Errorf(\"using nats based account resolver - the system account needs to be specified in configuration or the operator jwt\")\n\t\t}\n\t}\n\n\tsrvMajor, srvMinor, srvUpdate, _ := versionComponents(VERSION)\n\tfor _, opc := range o.TrustedOperators {\n\t\tif major, minor, update, err := jwt.ParseServerVersion(opc.AssertServerVersion); err != nil {\n\t\t\treturn fmt.Errorf(\"operator %s expects version %s got error instead: %s\",\n\t\t\t\topc.Subject, opc.AssertServerVersion, err)\n\t\t} else if major > srvMajor {\n\t\t\treturn fmt.Errorf(\"operator %s expected major version %d > server major version %d\",\n\t\t\t\topc.Subject, major, srvMajor)\n\t\t} else if srvMajor > major {\n\t\t} else if minor > srvMinor {\n\t\t\treturn fmt.Errorf(\"operator %s expected minor version %d > server minor version %d\",\n\t\t\t\topc.Subject, minor, srvMinor)\n\t\t} else if srvMinor > minor {\n\t\t} else if update > srvUpdate {\n\t\t\treturn fmt.Errorf(\"operator %s expected update version %d > server update version %d\",\n\t\t\t\topc.Subject, update, srvUpdate)\n\t\t}\n\t}\n\t// If we have operators, fill in the trusted keys.\n\t// FIXME(dlc) - We had TrustedKeys before TrustedOperators. The jwt.OperatorClaims\n\t// has a DidSign(). Use that longer term. For now we can expand in place.\n\tfor _, opc := range o.TrustedOperators {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/jwt.go#L112-L148","documentation":"Each operator claim carries AssertServerVersion; the server parses it during validation. If that version string is malformed, ParseServerVersion returns an error and the server wraps it here, refusing to start rather than guessing operator requirements.","triggerScenarios":"An operator JWT whose AssertServerVersion is not a valid semantic version (empty, typo, non-numeric); validateOptions fails while iterating TrustedOperators.","commonSituations":"Hand-crafted or older operator JWTs with a missing/invalid `assertServerVersion` claim; corrupting the JWT during manual editing.","solutions":["Re-sign the operator with a valid assert version: `nsc edit operator --account-url ...` / reissue so AssertServerVersion like \"2.10.0\" is set","Check the claim with `nsc describe operator` or decode the JWT and fix the assertion","Use a current nsc/nats-server version when generating operator JWTs"],"exampleFix":"// before (decoded operator claim)\n\"nats\": { \"assertServerVersion\": \"\" }\n// after\n\"nats\": { \"assertServerVersion\": \"2.10.1\" }","handlingStrategy":"validation","validationCode":"// Go: verify operator assertion parses before loading config\nif _, _, _, err := jwt.ParseServerVersion(opc.AssertServerVersion); err != nil {\n    return fmt.Errorf(\"operator %s has invalid assert version\", opc.Subject)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hand-edit operator JWTs; reissue via nsc","Decode and inspect operator claims with nsc before deployment","Regenerate old operators lacking a valid assertServerVersion"],"tags":["nats","jwt","version-validation","operator-mode"],"backgroundTag":"jwt-invalid-claims","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}