{"record":{"id":"893c597a3acedad9","repo":"nats-io/nats-server","slug":"default-sentinel-jwt-not-valid","errorCode":null,"errorMessage":"default sentinel JWT not valid","messagePattern":"default sentinel JWT not valid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/jwt.go","lineNumber":81,"sourceCode":"\t\tbuf[i] = 'x'\n\t}\n}\n\n// validateTrustedOperators will check that we do not have conflicts with\n// assigned trusted keys and trusted operators. If operators are defined we\n// will expand the trusted keys in options.\nfunc validateTrustedOperators(o *Options) error {\n\tif len(o.TrustedOperators) == 0 {\n\t\t// if we have no operator, default sentinel shouldn't be set\n\t\tif o.DefaultSentinel != _EMPTY_ {\n\t\t\treturn fmt.Errorf(\"default sentinel requires operators and accounts\")\n\t\t}\n\t\treturn nil\n\t}\n\tif o.DefaultSentinel != _EMPTY_ {\n\t\tjuc, err := jwt.DecodeUserClaims(o.DefaultSentinel)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"default sentinel JWT not valid\")\n\t\t}\n\n\t\tif !juc.BearerToken && juc.IssuerAccount != \"\" && juc.HasEmptyPermissions() {\n\t\t\t// we cannot resolve the account yet - but this looks like a scoped user\n\t\t\t// it will be rejected at runtime if not valid\n\t\t} else if !juc.BearerToken {\n\t\t\treturn fmt.Errorf(\"default sentinel must be a bearer token\")\n\t\t}\n\t}\n\tif o.AccountResolver == nil {\n\t\treturn fmt.Errorf(\"operators require an account resolver to be configured\")\n\t}\n\tif len(o.Accounts) > 0 {\n\t\treturn fmt.Errorf(\"operators do not allow Accounts to be configured directly\")\n\t}\n\tif len(o.Users) > 0 || len(o.Nkeys) > 0 {\n\t\treturn fmt.Errorf(\"operators do not allow users to be configured directly\")\n\t}","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/jwt.go#L63-L99","documentation":"validateTrustedOperators decodes the DefaultSentinel option with jwt.DecodeUserClaims; if the string is not a valid user claims JWT (malformed, wrong token type, bad signature structure), startup fails with 'default sentinel JWT not valid'. Note the error deliberately discards the underlying decode error detail.","triggerScenarios":"Setting default_sentinel in nats.conf (with operators configured) to a value that is not a decodable NATS user claims JWT — e.g. an account JWT, a truncated/pasted token, or a token produced by a different issuer/format.","commonSituations":"Copy/paste truncation of a long JWT in YAML/JSON config; mistaking an account or operator JWT for a user JWT; hand-editing a JWT that broke its base64 encoding.","solutions":["Verify the token with `nats auth` tooling or decode it (base64url of header/payload) to confirm it is a user claims JWT.","Regenerate the sentinel user JWT with `nsc` (nsc add user ... and export the bearer token).","Check for whitespace/newline corruption when embedding the JWT in the config; use block scalars carefully.","If the decode detail is needed, temporarily decode locally with github.com/nats-io/jwt/v2 DecodeUserClaims to see the real error."],"exampleFix":"// before\ndefault_sentinel: \"<account-jwt>\"  // wrong token type\n// after: use a user JWT (bearer) generated by nsc\ndefault_sentinel: \"eyJhbGciOi...user-claims-jwt\"","handlingStrategy":"validation","validationCode":"// Go: verify the JWT decodes as user claims before configuring\n_, err := jwt.DecodeUserClaims(sentinelJWT)\nif err != nil {\n    return fmt.Errorf(\"default_sentinel is not a valid user claims JWT: %v\", err)\n}","typeGuard":"func isUserClaimsJWT(tok string) bool {\n    _, err := jwt.DecodeUserClaims(tok)\n    return err == nil\n}","tryCatchPattern":null,"preventionTips":["Generate the sentinel JWT with nsc rather than hand-editing.","Validate the token decodes before pasting it into nats.conf.","Use config tests (`nats-server -t`) on startup scripts.","Store JWTs in files and reference them carefully to avoid truncation."],"tags":["config","authentication","jwt","operator-mode"],"backgroundTag":"jwt-invalid","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}