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

  1. Wait until the token's `nbf` time has passed, or request a token whose `nbf` is now or in the past.
  2. Add leeway: new LooseValidAt($clock, DateInterval::createFromDateString('30 seconds')) to tolerate small clock skew.
  3. Fix the issuer to not set `nbf` in the future unless intentionally scheduling (->cannotBeUsedBefore(...) only when needed).
  4. 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

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


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)