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

  1. Inspect the exception cause to see the underlying decode error (often IllegalArgumentException for bad characters).
  2. Verify the input contains only base64url-safe characters (A-Z, a-z, 0-9, '-', '_') with no padding, whitespace, or line breaks.
  3. Ensure the token is complete and not truncated by transport (URL length limits, logging truncation).
  4. 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

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


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/5ee1d0e4874d157a. Report an issue: GitHub.