lcobucci/jwt · error · Lcobucci\JWT\Encoding\CannotDecodeContent
Error while decoding from Base64Url, invalid base64…
Error message
Error while decoding from Base64Url, invalid base64 characters detected
What it means
This error wraps a low-level failure when decoding a Base64Url-encoded string in SodiumBase64Polyfill::base642bin. When the native sodium_base642bin() throws SodiumException (invalid base64 characters), the polyfill converts it into CannotDecodeContent::invalidBase64String(). It means the input string is not valid Base64Url data — usually it contains '+', '/', '=' or other non-URL-safe characters, or is corrupted/truncated.
Solutions
- Inspect the input string for illegal characters and strip/normalize '=' padding and whitespace before decoding
- Convert standard base64 to base64url first: strtr($value, '+/', '-_') and rtrim($value, '=')
- Verify the JWT is complete and was not truncated or mangled during transport/storage
- If you control the encoder, encode with SodiumBase64Polyfill::bin2base64($data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING)
- Wrap the decode in try-catch for CannotDecodeContent and surface a clear 'invalid token encoding' message to the caller
Example fix
// before $decoded = SodiumBase64Polyfill::base642bin($value, SODIUM_BASE64_VARIANT_URLSAFE); // after $value = rtrim(strtr($value, '+/', '-_'), '='); $decoded = SodiumBase64Polyfill::base642bin($value, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING);
Defensive patterns
Strategy: try-catch
Validate before calling
if (!preg_match('/^[A-Za-z0-9_-]*$/', $input)) { throw new InvalidArgumentException('Invalid base64url'); } Type guard
function isValidBase64Url(string $s): bool { return preg_match('/^[A-Za-z0-9_-]*$/', $s) === 1; } Try / catch
try { $decoded = SodiumBase64Polyfill::base64UrlDecode($input); } catch (Lcobucci\JWT\Encoding\CannotDecodeContent $e) { return error_400('Malformed token encoding'); } Prevention
- Normalize input to base64url (strtr + rtrim '='), before decoding
- Regex-validate token segments before decode
- Always catch CannotDecodeContent at the boundary (middleware) rather than letting it 500
When it happens
Trigger: Calling base64UrlDecode() or base642bin() on a string that contains standard-Base64 characters ('+','/') instead of Base64Url ('-','_'), padding '=' characters, whitespace, or any corrupted bytes. Also raised indirectly by parser signature decoding (signatureValidationWithLocalFileKeyReferenceWillOperateWithKeyContents, initializeKey call sites) when a JWT segment is not valid Base64Url.
Common situations: Passing a regular base64-encoded token into a Base64Url decoder; copying a JWT from a source that replaced '-'/'_' with '+'/'/'; appending '=' padding that Base64Url forbids; decoding a signed payload with a truncated or tampered segment.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Error while encoding to JSON
- Builder#withClaim() is meant to be used for non-registered…
- 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/fbe8fed4ae438946.
Report an issue: GitHub.
Appendix: source
Thrown at src/SodiumBase64Polyfill.php:72
return $encoded;
}
/**
* @return ($encoded is non-empty-string ? non-empty-string : string)
*
* @throws CannotDecodeContent
*/
public static function base642bin(string $encoded, int $variant): string
{
if (! function_exists('sodium_base642bin')) {
return self::base642binFallback($encoded, $variant); // @codeCoverageIgnore
}
try {
return sodium_base642bin($encoded, $variant, '');
} catch (SodiumException) {
throw CannotDecodeContent::invalidBase64String();
}
}
/**
* @return ($encoded is non-empty-string ? non-empty-string : string)
*
* @throws CannotDecodeContent
*/
public static function base642binFallback(string $encoded, int $variant): string
{
if (
$variant === self::SODIUM_BASE64_VARIANT_URLSAFE
|| $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
) {
$encoded = strtr($encoded, '-_', '+/');
}
$decoded = base64_decode($encoded, true);View on GitHub (pinned to 375813049c)