lcobucci/jwt · error · Lcobucci\JWT\Validation\Constraint\CannotValidateARegisteredClaim
The claim " " is a registered claim, another constraint…
Error message
The claim "{claim}" is a registered claim, another constraint must be used to validate its value What it means
HasClaimWithValue validates the exact value of a custom claim and, like HasClaim, refuses registered claims (iss, sub, aud, exp, nbf, iat, jti) because dedicated constraints exist for them. Constructing it with a registered claim name throws CannotValidateARegisteredClaim immediately.
Solutions
- Use the dedicated constraints: RelatedTo (sub), PermittedFor (aud), IssuedBy (iss), ValidAt (exp/nbf/iat), IdentifiedBy (jti)
- Read and compare registered claims manually via $token->claims()->get() if a dedicated constraint doesn't fit
- Rename your custom claim if it collides with a registered name
Example fix
// before
$c = new HasClaimWithValue('aud', 'my-api');
// after
$c = new PermittedFor('my-api'); Defensive patterns
Strategy: type-guard
Validate before calling
if (in_array($claimName, Token\RegisteredClaims::ALL, true)) {
// use RelatedTo / PermittedFor / IssuedBy / ValidAt instead
} Type guard
function isCustomClaim(string $claim): bool {
return !in_array($claim, Token\RegisteredClaims::ALL, true);
} Try / catch
try {
$constraint = new HasClaimWithValue('role', 'admin');
} catch (CannotValidateARegisteredClaim $e) {
// pick the dedicated constraint for that registered claim
} Prevention
- Never pass iss/sub/aud/exp/nbf/iat/jti to generic constraints
- Use a constraint factory mapping claim names to constraint classes
- Unit-test constraint construction with your claim allowlist
When it happens
Trigger: new HasClaimWithValue('sub', '123'), new HasClaimWithValue('aud', 'api'), new HasClaimWithValue('exp', ...), etc., i.e. any Token\RegisteredClaims::ALL member as the claim name.
Common situations: Checking issuer/audience values with the generic constraint instead of IssuedBy/PermittedFor; copy-pasting HasClaimWithValue and editing only the expected value; misunderstanding which claims are 'registered'.
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
- The claim " " is a registered claim, another constraint…
- You should pass a plain token
- You should pass a plain token
- No constraint given.
- The token does not have the claim
AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14).
Data as JSON: /api/errors/549d2644a4679b40.
Report an issue: GitHub.
Appendix: source
Thrown at src/Validation/Constraint/HasClaimWithValue.php:19
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Token;
use Lcobucci\JWT\UnencryptedToken;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\ConstraintViolation;
use function in_array;
final readonly class HasClaimWithValue implements Constraint
{
/** @param non-empty-string $claim */
public function __construct(private string $claim, private mixed $expectedValue)
{
if (in_array($claim, Token\RegisteredClaims::ALL, true)) {
throw CannotValidateARegisteredClaim::create($claim);
}
}
public function assert(Token $token): void
{
if (! $token instanceof UnencryptedToken) {
throw ConstraintViolation::error('You should pass a plain token', $this);
}
$claims = $token->claims();
if (! $claims->has($this->claim)) {
throw ConstraintViolation::error('The token does not have the claim "' . $this->claim . '"', $this);
}
if ($claims->get($this->claim) !== $this->expectedValue) {
throw ConstraintViolation::error(
'The claim "' . $this->claim . '" does not have the expected value',View on GitHub (pinned to 375813049c)