lcobucci/jwt · error · LeewayCannotBeNegative
Leeway cannot be negative
Error message
Leeway cannot be negative
What it means
StrictValidAt validates a token's iat/nbf/exp claims strictly against the current time, allowing an optional DateInterval leeway for clock skew. In its constructor, guardLeeway rejects a leeway interval created with invert=1 (a negative interval) because negative leeway is meaningless — the exception is LeewayCannotBeNegative. Leeway must be zero or a positive duration.
Solutions
- Use a positive DateInterval, e.g. new DateInterval('PT10M') for 10 minutes of leeway
- Check the source string for a leading minus sign when using DateInterval::createFromDateString()
- Pass null to use the default zero leeway if clock skew is not a concern
Example fix
// before
new StrictValidAt($clock, DateInterval::createFromDateString('-10 minutes'));
// after
new StrictValidAt($clock, DateInterval::createFromDateString('10 minutes')); Defensive patterns
Strategy: validation
Validate before calling
$leeway = DateInterval::createFromDateString('10 minutes');
if ($leeway->invert === 1) { throw new InvalidArgumentException('Leeway must not be negative'); } Type guard
function isValidLeeway(?DateInterval $leeway): bool { return $leeway === null || $leeway->invert === 0; } Try / catch
try {
$constraint = new StrictValidAt($clock, $leeway);
} catch (LeewayCannotBeNegative $e) {
$leeway = new DateInterval('PT0S'); // or correct config
} Prevention
- Never prefix leeway strings with '-' when constructing from date strings
- Add config validation that rejects negative durations at boot time
- Unit-test constraint construction with the exact values from your config files
When it happens
Trigger: new StrictValidAt($clock, new DateInterval('PT-5M')) or any DateInterval constructed via createFromDateString() with a negative spec (e.g. '-5 minutes') — DateInterval::invert is 1 for negative intervals.
Common situations: Typo like '-10 minutes' instead of '10 minutes' when configuring clock skew tolerance; computing the leeway by subtracting dates (DateTimeImmutable diff never does this, but manual math can); copying config from a library where negative leeway means 'past-only'.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Key cannot be empty
- No constraint given.
- Error while encoding to JSON
- Key provided is shorter than
- The type of the provided key is not
AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14).
Data as JSON: /api/errors/28c47eced3fc5b4c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Validation/Constraint/StrictValidAt.php:30
use Psr\Clock\ClockInterface as Clock;
final readonly class StrictValidAt implements ValidAtInterface
{
private DateInterval $leeway;
public function __construct(private Clock $clock, ?DateInterval $leeway = null)
{
$this->leeway = $this->guardLeeway($leeway);
}
private function guardLeeway(?DateInterval $leeway): DateInterval
{
if ($leeway === null) {
return new DateInterval('PT0S');
}
if ($leeway->invert === 1) {
throw LeewayCannotBeNegative::create();
}
return $leeway;
}
public function assert(Token $token): void
{
if (! $token instanceof UnencryptedToken) {
throw ConstraintViolation::error('You should pass a plain token', $this);
}
$now = $this->clock->now();
$this->assertIssueTime($token, $now->add($this->leeway));
$this->assertMinimumTime($token, $now->add($this->leeway));
$this->assertExpiration($token, $now->sub($this->leeway));
}
View on GitHub (pinned to 375813049c)