{"record":{"id":"6bc0d5efa69487d9","repo":"lcobucci/jwt","slug":"the-claim-claim-is-a-registered-claim-another-constraint","errorCode":null,"errorMessage":"The claim \"{claim}\" is a registered claim, another constraint must be used to validate its value","messagePattern":"The claim \"(.+?)\" is a registered claim, another constraint must be used to validate its value","errorType":"exception","errorClass":"Lcobucci\\JWT\\Validation\\Constraint\\CannotValidateARegisteredClaim","httpStatus":null,"severity":"error","filePath":"src/Validation/Constraint/HasClaim.php","lineNumber":19,"sourceCode":"<?php\ndeclare(strict_types=1);\n\nnamespace Lcobucci\\JWT\\Validation\\Constraint;\n\nuse Lcobucci\\JWT\\Token;\nuse Lcobucci\\JWT\\UnencryptedToken;\nuse Lcobucci\\JWT\\Validation\\Constraint;\nuse Lcobucci\\JWT\\Validation\\ConstraintViolation;\n\nuse function in_array;\n\nfinal readonly class HasClaim implements Constraint\n{\n    /** @param non-empty-string $claim */\n    public function __construct(private string $claim)\n    {\n        if (in_array($claim, Token\\RegisteredClaims::ALL, true)) {\n            throw CannotValidateARegisteredClaim::create($claim);\n        }\n    }\n\n    public function assert(Token $token): void\n    {\n        if (! $token instanceof UnencryptedToken) {\n            throw ConstraintViolation::error('You should pass a plain token', $this);\n        }\n\n        $claims = $token->claims();\n\n        if (! $claims->has($this->claim)) {\n            throw ConstraintViolation::error('The token does not have the claim \"' . $this->claim . '\"', $this);\n        }\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/lcobucci/jwt/blob/375813049c24c7111bda8b6884c57b071ceb2fe7/src/Validation/Constraint/HasClaim.php#L1-L36","documentation":"HasClaim is intended only for custom (private) claims; registered claims such as iss, sub, aud, exp, nbf, iat, jti have dedicated constraints that know how to validate their values. Constructing HasClaim with a registered claim name immediately throws CannotValidateARegisteredClaim. This steers you to the correct, stricter constraint.","triggerScenarios":"new HasClaim('iss'), new HasClaim('sub'), new HasClaim('aud'), new HasClaim('exp'), new HasClaim('nbf'), new HasClaim('iat'), new HasClaim('jti') (any entry of Token\\RegisteredClaims::ALL).","commonSituations":"Developers unfamiliar with the dedicated constraints reaching for the generic HasClaim to check standard claims like issuer or expiry; migrating code that previously just checked claim presence.","solutions":["Use the dedicated constraint for that claim (e.g. IssuedBy, ValidAt, IdentifiedBy, RelatedTo, PermittedFor)","If you only need presence of a registered claim, read $token->claims()->get('iss') directly and assert yourself","Register the custom claim name instead if it was accidentally named like a registered claim"],"exampleFix":"// before\n$constraint = new HasClaim('iss');\n// after\n$constraint = new IssuedBy('https://issuer.example.com');","handlingStrategy":"type-guard","validationCode":"if (in_array($claimName, \\Jose\\Component\\Signature\\Token\\RegisteredClaims::ALL, true)) {\n    // use the dedicated constraint instead\n}","typeGuard":"function isCustomClaim(string $claim): bool {\n    return !in_array($claim, Token\\RegisteredClaims::ALL, true);\n}","tryCatchPattern":"try {\n    $constraint = new HasClaim('my_claim');\n} catch (CannotValidateARegisteredClaim $e) {\n    // fall back to the dedicated registered-claim constraint\n}","preventionTips":["Consult Token\\RegisteredClaims::ALL before using generic constraints","Map registered claims to their dedicated constraints (IssuedBy, ValidAt, ...)","Wrap constraint construction in a factory that picks the right class"],"tags":["jwt","validation","constraint","misuse"],"backgroundTag":"invalid-argument-value","analyzedSha":"375813049c24c7111bda8b6884c57b071ceb2fe7","analyzedAt":"2026-09-14T11:12:28.004Z","contentChangedAt":"2026-09-14T11:12:28.004Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}