nats-io/nats-server · error
user JWT is not valid: %v
Error message
user JWT is not valid: %v
What it means
The user JWT's issuer was a known scoped signing key on the target account, but scope.ValidateScopedSigner(arc) failed: the claims do not satisfy the restrictions of that signing key's scope (e.g. disallowed permission templates, bearer token constraints, or other scoped-signer rules violated). The server rejects the user JWT as invalid.
Source
Thrown at server/auth_callout.go:237
// only allow placement if we are not in operator mode
placement = arc.Audience
} else {
placement = issuerAccount
}
targetAcc, err := s.LookupAccount(placement)
if err != nil {
return nil, fmt.Errorf("no valid account %q for auth callout response on account %q: %v", placement, account, err)
}
if isOperatorMode {
// this will validate the signing key that emitted the user, and if it is a signing
// key it assigns the permissions from the target account
if scope, ok := targetAcc.hasIssuer(arc.Issuer); !ok {
return nil, fmt.Errorf("user JWT issuer %q is not known", arc.Issuer)
} else if scope != nil {
// this possibly has to be different because it could just be a plain issued by a non-scoped signing key
if err := scope.ValidateScopedSigner(arc); err != nil {
return nil, fmt.Errorf("user JWT is not valid: %v", err)
} else if uSc, ok := scope.(*jwt.UserScope); !ok {
return nil, fmt.Errorf("user JWT is not a valid scoped user")
} else if arc.User.UserPermissionLimits, err = processUserPermissionsTemplate(uSc.Template, arc, targetAcc); err != nil {
return nil, fmt.Errorf("user JWT generated invalid permissions: %v", err)
}
}
}
return targetAcc, nil
}
processReply := func(_ *subscription, rc *client, racc *Account, subject, reply string, rmsg []byte) {
arc, err := decodeResponse(rc, rmsg, racc)
if err != nil {
c.authViolation()
respCh <- titleCase(err.Error())
return
}
// If the caller had established that the user should go through a proxy,View on GitHub (pinned to 3a66a489d2)
Solutions
- Read the wrapped %v detail from ValidateScopedSigner and align the user claims with the scope's restrictions.
- Regenerate the signing key scope with nsc so the callout's emitted permissions fit the template.
- Sign with a non-scoped account signing key if the callout needs unrestricted claim shapes (and the account JWT permits it).
- Update the callout's claim construction to honor the UserScope template (see processUserPermissionsTemplate usage).
Example fix
// before
arc.User.UserPermissionLimits.Pub.Allow = []string{"{">", "all-subjects"} // outside scope template
// after
arc.User.UserPermissionLimits.Pub.Allow = []string{"service.subjects.only"} // within the scoped signer template Defensive patterns
Strategy: validation
Validate before calling
scope, ok := targetAccScopes[arc.Issuer]
if ok {
if err := scope.ValidateScopedSigner(arc); err != nil {
return fmt.Errorf("claims violate scoped signer: %v", err)
}
} Try / catch
if err != nil && strings.Contains(err.Error(), "user JWT is not valid") {
// read the wrapped ValidateScopedSigner detail and fix claim shape
} Prevention
- Mirror the UserScope template's permission shape when building claims in the callout.
- Run ValidateScopedSigner in the callout before publishing the response.
- Regenerate scopes and callout claim logic together when scopes change.
When it happens
Trigger: Operator-mode callout signs a user JWT with a scoped signing key whose UserScope requirements are not met by the emitted claims — ValidateScopedSigner returns a non-nil err which is wrapped here.
Common situations: Callout building permissions that violate the scope's template (e.g. adding pub/sub subjects outside the scoped template); using a scoped key while emitting claims incompatible with scope limits after an nsc/scopes change.
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_
- wrong issuer for auth callout response on account %q, expect
- account %q not permitted as valid account option for auth ca
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/31cb2a6aecf937de.
Report an issue: GitHub.