lcobucci/jwt · error · ConstraintViolation
Constraint Violation triggered by one of the following:\n
Error message
Constraint Violation triggered by one of the following:\n- <accumulated violation messages>
What it means
SignedWithOneInSet wraps multiple SignedWith constraints and passes if at least one verifies the signature. If every constraint in the set throws ConstraintViolation, it re-throws a single ConstraintViolation whose message is 'Constraint Violation triggered by one of the following:' followed by each child violation message on its own line. This aggregates all failure reasons so the caller knows why each key/signer combination failed.
Solutions
- Read the accumulated '- ...' lines in the message to see which key/signer each candidate failed for
- Add the missing public key / signer to the set that actually signs the tokens
- Remove rotated keys from the set if tokens should no longer verify with them, and reissue tokens
- Verify each key in the set independently to isolate which one is misconfigured
Example fix
// before new SignedWithOneInSet(new SignedWith(new Sha256(), $oldKey), new SignedWith(new Sha256(), $newKey)); // after (include the key the token was actually signed with) new SignedWithOneInSet(new SignedWith(new Sha256(), $oldKey), new SignedWith(new Sha256(), $newKey), new SignedWith(new Sha256(), $rotatedOutKey));
Defensive patterns
Strategy: try-catch
Validate before calling
foreach ($candidates as $key) {
try { (new Validator())->assert($token, new SignedWith(new Sha256(), $key)); return true; } catch (ConstraintViolation) {}
}
return false; Type guard
null
Try / catch
try {
$validator->assert($token, $signedWithOneInSet);
} catch (ConstraintViolation $e) {
// $e->getMessage() lists each candidate's failure; route to key-rotation fallback
} Prevention
- Keep the key set in sync with all keys that could plausibly have signed live tokens
- Drop truly revoked keys and force reissue rather than leaving tokens unverifiable
- Log the per-constraint messages to diagnose which key candidate mismatched
When it happens
Trigger: Validator::assert($token, new SignedWithOneInSet(...$signedWithConstraints)) where none of the supplied SignedWith constraints verify the token signature — every child throws and the accumulated messages are bundled.
Common situations: Key rotation setups where the old and new keys are both listed but the token was signed with a third (revoked) key; multiple issuer keys configured but token came from an unlisted issuer; PEM public key content pasted incorrectly so all candidates fail.
Related errors
- Token signature mismatch
- No constraint given.
- The JWT string is missing the Signature part
- The claim " " is a registered claim, another constraint…
- You should pass a plain token
AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14).
Data as JSON: /api/errors/0634d3f63bba6b42.
Report an issue: GitHub.
Appendix: source
Thrown at src/Validation/Constraint/SignedWithOneInSet.php:36
{
$this->constraints = $constraints;
}
public function assert(Token $token): void
{
$errorMessage = 'It was not possible to verify the signature of the token, reasons:';
foreach ($this->constraints as $constraint) {
try {
$constraint->assert($token);
return;
} catch (ConstraintViolation $violation) {
$errorMessage .= PHP_EOL . '- ' . $violation->getMessage();
}
}
throw ConstraintViolation::error($errorMessage, $this);
}
}
View on GitHub (pinned to 375813049c)