Skip to content
ecdsa.com
Java (JDK)Java

Error message

java.lang.IllegalArgumentException: Illegal base64 character 2d

Also printed as

  • java.lang.IllegalArgumentException: Illegal base64 character a
  • java.lang.IllegalArgumentException: Illegal base64 character d
  • java.lang.IllegalArgumentException: Illegal base64 character 5f
  • java.lang.IllegalArgumentException: Illegal base64 character 20

The hex value names the offending character: `2d` '-', `5f` '_', `a` LF, `d` CR, `20` space.

Java (JDK) — java.util.Base64.Decoder.decode

What it means

`Base64.getDecoder()` is the strict RFC 4648 decoder: it accepts only `A–Z a–z 0–9 + /` and `=` padding, and stops at the first other character. The hex number is that character's code: `2d` is `-` (the dashes of `-----BEGIN …-----`, or the base64url alphabet), `a` is a line feed, `d` a carriage return, `20` a space, `5f` an underscore. The data is usually fine — it is in a different textual wrapping than the decoder expects.

Why it happens

How to fix it

  1. 1.

    Strip the armour and use the MIME decoder

    `Base64.getMimeDecoder()` skips line separators, which is exactly what PEM bodies need.

    java
    String body = pem.replaceAll("-----(BEGIN|END) [A-Z ]+-----", "");
    byte[] der = Base64.getMimeDecoder().decode(body); // ignores line separators and other non-alphabet characters
  2. 2.

    Use the URL decoder for JOSE data

    Everything in a JWT and in a JWK is base64url; the URL decoder also accepts the missing padding.

    java
    // JWT segments and JWK fields ("x", "y", "n", "e") use base64url without padding.
    byte[] header = Base64.getUrlDecoder().decode(jwt.split("\\.")[0]);
    byte[] x = Base64.getUrlDecoder().decode(jwk.get("x"));

Related errors

Browse the full signature error database