jwtk/jjwt · error · java.lang.IllegalArgumentException
Strict decoding: Last encoded character (before the…
Error message
Strict decoding: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible encoding. Expected the discarded bits from the character to be zero.
What it means
Error "Strict decoding: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible encoding. Expected the discarded bits from the character to be zero." thrown in jwtk/jjwt.
Solutions
- Re-encode the input with a standards-compliant Base64 encoder so the unused low bits of the final character are zero (strict/RFC 4648 canonical encoding)
- Regenerate or re-fetch the token/data, since non-canonical padding bits usually indicate corruption or a non-conformant encoder
- If lenient decoding of legacy data is required, decode without strict mode rather than altering the strict decoder
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at impl/src/main/java/io/jsonwebtoken/impl/io/Base64Codec.java:774 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/6c28f0dce7355669.
Report an issue: GitHub.
Appendix: source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/io/Base64Codec.java:774
public boolean isUrlSafe() {
return this.encodeTable == URL_SAFE_ENCODE_TABLE;
}
/**
* Validates whether decoding the final trailing character is possible in the context
* of the set of possible base 64 values.
* <p>
* The character is valid if the lower bits within the provided mask are zero. This
* is used to test the final trailing base-64 digit is zero in the bits that will be discarded.
* </p>
*
* @param emptyBitsMask The mask of the lower bits that should be empty
* @param context the context to be used
* @throws IllegalArgumentException if the bits being checked contain any non-zero value
*/
private void validateCharacter(final int emptyBitsMask, final Context context) {
if (isStrictDecoding() && (context.ibitWorkArea & emptyBitsMask) != 0) {
throw new IllegalArgumentException(
"Strict decoding: Last encoded character (before the paddings if any) is a valid " +
"base 64 alphabet but not a possible encoding. " +
"Expected the discarded bits from the character to be zero.");
}
}
/**
* Validates whether decoding allows an entire final trailing character that cannot be
* used for a complete byte.
*
* @throws IllegalArgumentException if strict decoding is enabled
*/
private void validateTrailingCharacter() {
if (isStrictDecoding()) {
throw new IllegalArgumentException(
"Strict decoding: Last encoded character (before the paddings if any) is a valid " +
"base 64 alphabet but not a possible encoding. " +
"Decoding requires at least two trailing 6-bit characters to create bytes.");View on GitHub (pinned to fb71496164)