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

  1. Use the dedicated constraints: RelatedTo (sub), PermittedFor (aud), IssuedBy (iss), ValidAt (exp/nbf/iat), IdentifiedBy (jti)
  2. Read and compare registered claims manually via $token->claims()->get() if a dedicated constraint doesn't fit
  3. 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

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


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)