{"record":{"id":"e727436e56353c3e","repo":"nats-io/nats-server","slug":"error-non-operator-mode-account-q-attempted-to-u","errorCode":null,"errorMessage":"error non operator mode account %q: attempted to use issuer_account","messagePattern":"error non operator mode account %q: attempted to use issuer_account","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/auth_callout.go","lineNumber":175,"sourceCode":"\t// only in operator mode we expect to receive `issuer_account`.\n\tgetIssuerAccount := func(arc *jwt.UserClaims, account string) (string, error) {\n\t\t// Make sure correct issuer.\n\t\tvar issuer string\n\t\tif opts.AuthCallout != nil {\n\t\t\tissuer = opts.AuthCallout.Issuer\n\t\t} else {\n\t\t\t// Operator mode is who we send the request on unless switching accounts.\n\t\t\tissuer = acc.Name\n\t\t}\n\n\t\t// the jwt issuer can be a signing key\n\t\tjwtIssuer := arc.Issuer\n\t\tif arc.IssuerAccount != _EMPTY_ {\n\t\t\tif !isOperatorMode {\n\t\t\t\t// this should be invalid - effectively it would allow the auth callout\n\t\t\t\t// to issue on another account which may be allowed given the configuration\n\t\t\t\t// where the auth callout account can handle multiple different ones..\n\t\t\t\treturn _EMPTY_, fmt.Errorf(\"error non operator mode account %q: attempted to use issuer_account\", account)\n\t\t\t}\n\t\t\tjwtIssuer = arc.IssuerAccount\n\t\t}\n\n\t\tif jwtIssuer != issuer {\n\t\t\tif !isOperatorMode {\n\t\t\t\treturn _EMPTY_, fmt.Errorf(\"wrong issuer for auth callout response on account %q, expected %q got %q\", account, issuer, jwtIssuer)\n\t\t\t} else if !acc.isAllowedAcount(jwtIssuer) {\n\t\t\t\treturn _EMPTY_, fmt.Errorf(\"account %q not permitted as valid account option for auth callout for account %q\",\n\t\t\t\t\tarc.Issuer, account)\n\t\t\t}\n\t\t}\n\t\treturn jwtIssuer, nil\n\t}\n\n\tgetExpirationAndAllowedConnections := func(arc *jwt.UserClaims, account string) (time.Duration, map[string]struct{}, error) {\n\t\tallowNow, expiration := validateTimes(arc)\n\t\tif !allowNow {","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/auth_callout.go#L157-L193","documentation":"In non-operator mode, the auth callout response's user JWT set an IssuerAccount, which is illegal: it would let the callout effectively issue users on a different account. The server rejects the response outright. IssuerAccount is only meaningful in operator (decentralized JWT) mode.","triggerScenarios":"A callout service builds AuthorizationResponseClaims/UserClaims with IssuerAccount populated while the server runs without an operator (account/server-local auth callout), then the user connects.","commonSituations":"Reusing callout code written for operator-mode deployments in a plain server setup; blindly copying example configs that set IssuerAccount.","solutions":["Remove IssuerAccount from the claims the callout emits; rely on Issuer only.","If per-account issuing is needed, run the deployment in operator mode with a proper account JWT.","Verify the server's mode (operator vs local) matches what the callout service assumes."],"exampleFix":"// before\narc.IssuerAccount = calloutAccountPub\n// after\narc.IssuerAccount = _EMPTY_ // not allowed in non-operator mode\narc.Issuer = calloutAccountPub","handlingStrategy":"validation","validationCode":"if arc.IssuerAccount != \"\" && !operatorMode {\n    return errors.New(\"issuer_account not permitted in non-operator mode\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never set IssuerAccount unless running in operator mode.","Share claim-building code conditionally on deployment mode.","Add a pre-publish Validate check in the callout for this field."],"tags":["auth-callout","jwt","operator-mode"],"backgroundTag":"auth-callout-issuer-mismatch","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}