jwtk/jjwt · error · io.jsonwebtoken.io.DecodingException
Unable to ${codecName}-decode ${name}: ${t.getMessage()}
Error message
Unable to ${codecName}-decode ${name}: ${t.getMessage()} What it means
Thrown as a DecodingException when a decoding stream operation fails while Base64/base64url-decoding the named input. The wrapper class (DecodingInputStream) catches any Throwable raised during codec-decoding and rewraps it with a message naming the codec and the input name. The original cause is preserved as the exception cause for diagnosis.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/io/DecodingInputStream.java:37
import io.jsonwebtoken.lang.Assert;
import java.io.InputStream;
public class DecodingInputStream extends FilteredInputStream {
private final String codecName;
private final String name;
public DecodingInputStream(InputStream in, String codecName, String name) {
super(in);
this.codecName = Assert.hasText(codecName, "codecName cannot be null or empty.");
this.name = Assert.hasText(name, "Name cannot be null or empty.");
}
@Override
protected void onThrowable(Throwable t) {
String msg = "Unable to " + this.codecName + "-decode " + this.name + ": " + t.getMessage();
throw new DecodingException(msg, t);
}
}
View on GitHub (pinned to fb71496164)
Solutions
- Inspect the exception cause to see the underlying decode error (often IllegalArgumentException for bad characters).
- Verify the input contains only base64url-safe characters (A-Z, a-z, 0-9, '-', '_') with no padding, whitespace, or line breaks.
- Ensure the token is complete and not truncated by transport (URL length limits, logging truncation).
- If the data came from another system, confirm it used base64url encoding, not standard Base64.
Example fix
// before
String token = someHeaderValue; // may contain '=' padding or whitespace
// after
String token = someHeaderValue.trim().replace("=", "").replace("+", "-").replace("/", "_"); Defensive patterns
Strategy: try-catch
Validate before calling
// Java
private static final Pattern B64URL = Pattern.compile("^[A-Za-z0-9_-]*$");
if (!B64URL.matcher(segment).matches()) {
throw new IllegalArgumentException("segment contains invalid base64url characters");
} Type guard
static boolean isBase64Url(String s) {
return s != null && s.matches("[A-Za-z0-9_-]*");
} Try / catch
try {
byte[] decoded = Decoders.BASE64URL.decode(segment);
} catch (DecodingException e) {
log.warn("Invalid base64url segment: {}", e.getMessage(), e.getCause());
throw new BadRequestException("Malformed token");
} Prevention
- Reject tokens with invalid base64url characters at your API boundary before invoking the parser.
- Trim whitespace and strip '=' padding from tokens received via headers or query params.
- Log the exception cause, not just the message, to diagnose character-level decode failures.
- Never round-trip JWTs through systems that re-encode strings (URL encoders, HTML escape layers).
When it happens
Trigger: Reading a JWT, JWS, or JWE compact part through DecodingInputStream when the underlying bytes are not valid base64url, or when the underlying InputStream throws (IO failure, truncated stream).
Common situations: Hand-editing tokens and introducing invalid characters (e.g. '+', '/', '=' or whitespace) into a base64url segment; tokens truncated by proxies or logs; passing raw binary data where a base64url string was expected.
Related errors
- Unable to Base64Url-decode InputStream: ${t.getMessage()}
- Unable to decode input: ${e.getMessage()}
- Invalid Base64Url <name>: <value>
- Unable to read compact JWT: ${e.getMessage()}
- JWA Base64urlUInt values MUST be >= 0 (non-negative) per the
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/5ee1d0e4874d157a.
Report an issue: GitHub.