Skip to content
Latchkey

JWT "jwt expired" (TokenExpiredError) in CI

The JWT verified structurally and by signature, but its exp claim is in the past. jsonwebtoken raises "TokenExpiredError: jwt expired" with the expiration timestamp.

What this error means

Verification throws "TokenExpiredError: jwt expired" with an expiredAt value. A hardcoded test token or a token minted before a slow test finished has aged out.

jsonwebtoken
TokenExpiredError: jwt expired
    at /app/node_modules/jsonwebtoken/verify.js:190:21
  expiredAt: 2026-06-29T10:00:00.000Z

Common causes

A stale hardcoded fixture token

A token committed to the repo has a fixed exp in the past, so it is expired every run.

Runner clock skew or a slow test

A short-lived token expires before verification if the job is slow or the runner clock differs from the issuer.

How to fix it

Mint tokens at test time

  1. Generate the JWT inside the test with a future exp instead of committing one.
  2. Use a generous expiresIn for fixtures so slow jobs do not age it out.
  3. Verify the runner clock is roughly correct.
test.js
const token = jwt.sign({ sub: 'ci' }, secret, { expiresIn: '1h' });

Allow small clock skew when appropriate

For provider tokens, set a small clockTolerance so minor runner clock drift does not reject a still-valid token.

test.js
jwt.verify(token, key, { clockTolerance: 30 });

How to prevent it

  • Generate fixture tokens at runtime with a future exp.
  • Keep runner clocks synchronized with the issuer.
  • Set a small clockTolerance for provider-issued tokens.

Frequently asked questions

What causes ""jwt expired""?
A token committed to the repo has a fixed exp in the past, so it is expired every run.
How do I fix "jwt expired"?
Mint tokens at test time

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card