lcobucci/jwt · error · Lcobucci\JWT\Token\RegisteredClaimGiven
Builder#withClaim() is meant to be used for non-registered…
Error message
Builder#withClaim() is meant to be used for non-registered claims, check the documentation on how to set claim "%s"
What it means
Builder::withClaim() is reserved for private (non-registered) claims. If the claim name is one of the IANA-registered JWT claims (iss, sub, aud, exp, nbf, iat, jti, etc.), the builder refuses and throws RegisteredClaimGiven::forClaim(), because registered claims need typed values and dedicated methods.
Solutions
- Use the dedicated builder methods: issuedBy(), relatedTo(), permittedFor(), identifiedBy(), canOnlyBeUsedAfter(), expiresAt(), issuedAt()
- For time claims pass DateTimeImmutable objects to expiresAt()/issuedAt()/canOnlyBeUsedAfter() rather than raw values via withClaim
- Keep withClaim() only for custom/private claim names not in RegisteredClaims::ALL
Example fix
// before
$builder->withClaim('iss', 'https://my.issuer')->withClaim('exp', time() + 3600);
// after
$builder->issuedBy('https://my.issuer')
->issuedAt(new DateTimeImmutable())
->expiresAt(new DateTimeImmutable('+1 hour')); Defensive patterns
Strategy: validation
Validate before calling
if (in_array($name, Lcobucci\JWT\Token\RegisteredClaims::ALL, true)) { useDedicatedBuilderMethod($name); } Prevention
- Learn the dedicated builder methods for registered claims (issuedBy, expiresAt, etc.)
- Restrict withClaim usage to custom names via code review or a thin wrapper API
- When migrating libraries, map every old generic set() call to the typed API
When it happens
Trigger: Calling $builder->withClaim('iss', ...), withClaim('exp', ...), withClaim('aud', ...) or any other name present in lcobucci\jwt\signing or Token\RegisteredClaims::ALL.
Common situations: Copy-pasted code building tokens that sets standard claims generically; migration from another JWT library where all claims were set through one method; setting 'exp' or 'iat' as raw ints instead of using the typed API (which handles DateTimeImmutable conversion).
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
- claims must be an array with non-empty-string keys
- Error while decoding from Base64Url, invalid base64…
- The JWT string is missing the Header part
- The JWT string is missing the Claim part
- The JWT string is missing the Signature part
AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14).
Data as JSON: /api/errors/dd27bb214af62798.
Report an issue: GitHub.
Appendix: source
Thrown at src/Token/Builder.php:95
}
public function withHeader(string $name, mixed $value): BuilderInterface
{
$headers = $this->headers;
$headers[$name] = $value;
return new self(
$this->encoder,
$this->claimFormatter,
$headers,
$this->claims,
);
}
public function withClaim(string $name, mixed $value): BuilderInterface
{
if (in_array($name, RegisteredClaims::ALL, true)) {
throw RegisteredClaimGiven::forClaim($name);
}
return $this->newWithClaim($name, $value);
}
/** @param non-empty-string $name */
private function newWithClaim(string $name, mixed $value): BuilderInterface
{
$claims = $this->claims;
$claims[$name] = $value;
return new self(
$this->encoder,
$this->claimFormatter,
$this->headers,
$claims,
);
}View on GitHub (pinned to 375813049c)