nats-io/nats-server · error
account expired
Error message
account expired
What it means
ErrAccountExpired is returned when an account has expired — its claims contain an expiry that has passed, so the server refuses to resolve or use the account. LookupAccount and related resolution paths surface it, and monitoring endpoints check for it (including err==nil with acc.IsExpired()).
Source
Thrown at server/errors.go:126
ErrReservedAccount = errors.New("reserved account")
// ErrMissingAccount is returned when an account does not exist.
ErrMissingAccount = errors.New("account missing")
// ErrMissingService is returned when an account does not have an exported service.
ErrMissingService = errors.New("service missing")
// ErrBadServiceType is returned when latency tracking is being applied to non-singleton response types.
ErrBadServiceType = errors.New("bad service response type")
// ErrBadSampling is returned when the sampling for latency tracking is not 1 >= sample <= 100.
ErrBadSampling = errors.New("bad sampling percentage, should be 1-100")
// ErrAccountValidation is returned when an account has failed validation.
ErrAccountValidation = errors.New("account validation failed")
// ErrAccountExpired is returned when an account has expired.
ErrAccountExpired = errors.New("account expired")
// ErrNoAccountResolver is returned when we attempt an update but do not have an account resolver.
ErrNoAccountResolver = errors.New("account resolver missing")
// ErrAccountResolverUpdateTooSoon is returned when we attempt an update too soon to last request.
ErrAccountResolverUpdateTooSoon = errors.New("account resolver update too soon")
// ErrAccountResolverSameClaims is returned when same claims have been fetched.
ErrAccountResolverSameClaims = errors.New("account resolver no new claims")
// ErrStreamImportAuthorization is returned when a stream import is not authorized.
ErrStreamImportAuthorization = errors.New("stream import not authorized")
// ErrStreamImportBadPrefix is returned when a stream import prefix contains wildcards.
ErrStreamImportBadPrefix = errors.New("stream import prefix can not contain wildcard tokens")
// ErrStreamImportDuplicate is returned when a stream import is a duplicate of one that already exists.
ErrStreamImportDuplicate = errors.New("stream import already exists")View on GitHub (pinned to 3a66a489d2)
Solutions
- Re-issue or renew the account JWT with a later/longer expiry (nsc update or push a new claim via $SYS.REQ.CLAIM.UPDATE)
- Push the renewed claim to the account resolver so lookups succeed
- Check system clock (NTP) if expiry appears to have passed prematurely
- If intentionally testing expiry handling, expect and match this error rather than treating it as fatal
Example fix
// before acc, err := s.LookupAccount(apub) // claim exp passed -> ErrAccountExpired // after newJWT := renewAccountJWT(apub, 24*time.Hour) // re-sign with future exp pushClaimToResolver(newJWT) acc, err := s.LookupAccount(apub)
Defensive patterns
Strategy: type-guard
Validate before calling
c, err := jwt.DecodeAccountClaims(accJWT)
if err == nil && c.ClaimsData.Expiration > 0 && c.ClaimsData.Expiration <= time.Now().Unix() { return errors.New("account claim already expired") } Type guard
func isAccountExpiredErr(err error) bool { return errors.Is(err, ErrAccountExpired) }
func accountIsExpired(acc *Account) bool { return acc != nil && acc.IsExpired() } Try / catch
acc, err := s.LookupAccount(apub)
if isAccountExpiredErr(err) { renewAccountJWT(apub); return } // handle expiry gracefully Prevention
- Renew account JWTs before expiry (monitor exp with alerts)
- Use NTP to keep server clocks accurate
- Prefer long-lived claims in production; short TTLs only for tests
When it happens
Trigger: LookupAccount on an account whose JWT exp claim is in the past; account resolver fetching an expired claim; monitor account-stats endpoints requesting an expired account (monitor.go:3747); JetStream flows checking errors.Is(err, ErrAccountExpired) (jetstream_jwt_test.go:1182).
Common situations: Operator-issued account credentials past their expiration date in long-lived deployments; test/dev accounts issued with short TTLs; system clock skew making a valid claim appear expired; forgetting to renew account JWTs in a resolver setup.
Related errors
- account validation failed
- account jwt not found
- auth callout violation: auth callout response is not for exp
- auth callout violation: auth callout response is not for ser
- auth callout signing key is unknown
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/efbacd2fcf8cdd66.
Report an issue: GitHub.