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

  1. Read the accumulated '- ...' lines in the message to see which key/signer each candidate failed for
  2. Add the missing public key / signer to the set that actually signs the tokens
  3. Remove rotated keys from the set if tokens should no longer verify with them, and reissue tokens
  4. 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

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


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)