lcobucci/jwt · error · ConstraintViolation
The token cannot be used yet
Error message
The token cannot be used yet
What it means
This ConstraintViolation is thrown by the LooseValidAt constraint when the token's `nbf` (not before) claim is in the future relative to the current time (adjusted by leeway). The library rejects tokens used before the start of their validity window.
Solutions
- Wait until the token's `nbf` time has passed, or request a token whose `nbf` is now or in the past.
- Add leeway: new LooseValidAt($clock, DateInterval::createFromDateString('30 seconds')) to tolerate small clock skew.
- Fix the issuer to not set `nbf` in the future unless intentionally scheduling (->cannotBeUsedBefore(...) only when needed).
- Compare $token->claims()->get('nbf') with your server time (NTP-synced) to determine whether clock skew is the cause.
Example fix
// before: token with future nbf rejected immediately
$validator->assert($token, [new LooseValidAt($clock)]); // 'cannot be used yet'
// after: tolerate 30s skew / near-future nbf
$validator->assert($token, [
new LooseValidAt($clock, DateInterval::createFromDateString('30 seconds')),
]); Defensive patterns
Strategy: try-catch
Validate before calling
$nbf = $token->claims()->get('nbf');
if ($nbf instanceof DateTimeInterface && $nbf->getTimestamp() > time() + $leewaySeconds) {
// token not usable yet: delay or reject
} Type guard
function isPastMinimumTime(Lcobucci\JWT\Token $token, int $leewaySeconds = 0): bool
{
$nbf = $token->claims()->get('nbf');
return ! $nbf instanceof DateTimeInterface
|| $nbf->getTimestamp() <= time() + $leewaySeconds;
} Try / catch
try {
$validator->assert($token, $constraints);
} catch (Lcobucci\JWT\Validation\ConstraintViolation $e) {
if ($e->getConstraint() instanceof Lcobucci\JWT\Validation\Constraint\LooseValidAt) {
// token not valid yet: schedule retry at nbf time
}
} Prevention
- Only set ->cannotBeUsedBefore() when you intentionally schedule future validity.
- NTP-sync issuer and verifier clocks.
- Use a small leeway in LooseValidAt to absorb second-level skew.
- When pre-issuing tokens, deliver them to consumers only at/after the nbf time.
When it happens
Trigger: LooseValidAt::assert($token) calls assertMinimumTime(), which throws when Token::isMinimumTimeBefore($now) returns false — i.e. the token carries an `nbf` claim later than ($now + leeway).
Common situations: Pre-issued tokens (e.g. scheduled jobs, invites, licenses) used before their `nbf` timestamp; validating a token seconds after issuance on a server whose clock lags behind the issuer's; issuing systems setting `nbf` too aggressively (future-dated) by mistake.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- The token is not identified with the expected ID
- The token was not issued by the given issuers
- The token is expired
- The token cannot be used yet
- No constraint given.
AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14).
Data as JSON: /api/errors/615afe41020638da.
Report an issue: GitHub.
Appendix: source
Thrown at src/Validation/Constraint/LooseValidAt.php:56
$this->assertIssueTime($token, $now->add($this->leeway));
$this->assertMinimumTime($token, $now->add($this->leeway));
$this->assertExpiration($token, $now->sub($this->leeway));
}
/** @throws ConstraintViolation */
private function assertExpiration(Token $token, DateTimeInterface $now): void
{
if ($token->isExpired($now)) {
throw ConstraintViolation::error('The token is expired', $this);
}
}
/** @throws ConstraintViolation */
private function assertMinimumTime(Token $token, DateTimeInterface $now): void
{
if (! $token->isMinimumTimeBefore($now)) {
throw ConstraintViolation::error('The token cannot be used yet', $this);
}
}
/** @throws ConstraintViolation */
private function assertIssueTime(Token $token, DateTimeInterface $now): void
{
if (! $token->hasBeenIssuedBefore($now)) {
throw ConstraintViolation::error('The token was issued in the future', $this);
}
}
}
View on GitHub (pinned to 375813049c)