nats-io/nats-server · error
wrong issuer for auth callout response on account %q, expect
Error message
wrong issuer for auth callout response on account %q, expected %q got %q
What it means
In non-operator mode, the Issuer of the auth callout response's user JWT does not match the expected issuer (the account/signing key the server expects for that account). The server rejects the response because the JWT was not signed by the authorized identity. This prevents a callout from minting users attributed to another issuer.
Source
Thrown at server/auth_callout.go:182
// Operator mode is who we send the request on unless switching accounts.
issuer = acc.Name
}
// the jwt issuer can be a signing key
jwtIssuer := arc.Issuer
if arc.IssuerAccount != _EMPTY_ {
if !isOperatorMode {
// this should be invalid - effectively it would allow the auth callout
// to issue on another account which may be allowed given the configuration
// where the auth callout account can handle multiple different ones..
return _EMPTY_, fmt.Errorf("error non operator mode account %q: attempted to use issuer_account", account)
}
jwtIssuer = arc.IssuerAccount
}
if jwtIssuer != issuer {
if !isOperatorMode {
return _EMPTY_, fmt.Errorf("wrong issuer for auth callout response on account %q, expected %q got %q", account, issuer, jwtIssuer)
} else if !acc.isAllowedAcount(jwtIssuer) {
return _EMPTY_, fmt.Errorf("account %q not permitted as valid account option for auth callout for account %q",
arc.Issuer, account)
}
}
return jwtIssuer, nil
}
getExpirationAndAllowedConnections := func(arc *jwt.UserClaims, account string) (time.Duration, map[string]struct{}, error) {
allowNow, expiration := validateTimes(arc)
if !allowNow {
c.Errorf("Outside connect times")
return 0, nil, fmt.Errorf("authorized user on account %q outside of valid connect times", account)
}
allowedConnTypes, err := convertAllowedConnectionTypes(arc.User.AllowedConnectionTypes)
if err != nil {
c.Debugf("%v", err)View on GitHub (pinned to 3a66a489d2)
Solutions
- Sign the user JWT with the issuer (account or its signing key) the server expects for the target account.
- Update the callout's configured signing key to match the account's current issuer after a key rotation.
- Check the error's expected/got values and align the callout's key selection.
- If multiple issuers are intended, switch to operator mode where allowed-account checks apply instead.
Example fix
// before signed, err := arc.Encode(calloutServiceNkey) // after signed, err := arc.Encode(targetAccountIssuerNkey) // must equal the account's issuer in non-operator mode
Defensive patterns
Strategy: validation
Validate before calling
if jwtIssuer := arc.Issuer; jwtIssuer != expectedIssuer {
return fmt.Errorf("issuer %q != expected %q", jwtIssuer, expectedIssuer)
} Prevention
- Configure the callout with the exact issuer the server expects per account.
- Re-verify signing keys after any account key rotation.
- Compare 'expected' vs 'got' in the error message when debugging.
When it happens
Trigger: The callout signs the user JWT with a signing key/nkey different from the account's expected issuer while the server runs in non-operator mode, so jwtIssuer != issuer.
Common situations: Callout configured with the wrong signing key or signing with the callout account key instead of the target account's key; rotating keys on the account without updating the callout.
Related errors
- operators do not allow authorization callouts to be configur
- authorization response had validation errors: %v
- error non operator mode account %q: attempted to use issuer_
- account %q not permitted as valid account option for auth ca
- authorized user on account %q outside of valid connect times
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/eb5ca4a82a8ab6bd.
Report an issue: GitHub.