jwtk/jjwt · error · MalformedJwtException

Compact JWE strings must always contain an Initialization Ve

Error message

Compact JWE strings must always contain an Initialization Vector.

What it means

RFC 7516 requires every compact JWE to carry an Initialization Vector, so after decoding the 'iv' segment the parser checks it decoded to non-empty bytes; if the segment is absent or empty it throws MalformedJwtException because AEAD decryption cannot proceed without an IV.

Source

Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:520

            Assert.stateNotNull(keyAlg, "JWE Key Algorithm cannot be null.");

            byte[] cekBytes = Bytes.EMPTY; //ignored unless using an encrypted key algorithm
            CharSequence base64Url = tokenizedJwe.getEncryptedKey();
            if (Strings.hasText(base64Url)) {
                cekBytes = decode(base64Url, "JWE encrypted key");
                if (Bytes.isEmpty(cekBytes)) {
                    String msg = "Compact JWE string represents an encrypted key, but the key is empty.";
                    throw new MalformedJwtException(msg);
                }
            }

            base64Url = tokenizedJwe.getIv();
            if (Strings.hasText(base64Url)) {
                iv = decode(base64Url, "JWE Initialization Vector");
            }
            if (Bytes.isEmpty(iv)) {
                String msg = "Compact JWE strings must always contain an Initialization Vector.";
                throw new MalformedJwtException(msg);
            }

            // The AAD (Additional Authenticated Data) scheme for compact JWEs is to use the ASCII bytes of the
            // raw base64url text as the AAD, and NOT the base64url-decoded bytes per
            // https://www.rfc-editor.org/rfc/rfc7516.html#section-5.1, Step 14.
            ByteBuffer buf = StandardCharsets.US_ASCII.encode(Strings.wrap(base64UrlHeader));
            final byte[] aadBytes = new byte[buf.remaining()];
            buf.get(aadBytes);
            InputStream aad = Streams.of(aadBytes);

            base64Url = base64UrlDigest;
            //guaranteed to be non-empty via the `alg` + digest check above:
            Assert.hasText(base64Url, "JWE AAD Authentication Tag cannot be null or empty.");
            digest = decode(base64Url, "JWE AAD Authentication Tag");
            if (Bytes.isEmpty(digest)) {
                String msg = "Compact JWE strings must always contain an AAD Authentication Tag.";
                throw new MalformedJwtException(msg);
            }

View on GitHub (pinned to fb71496164)

Solutions

  1. Ensure you are parsing the right token type: JWS strings have no IV; use the JWS API for them.
  2. Regenerate the JWE with a valid producer so the IV segment is populated (all standard JWE enc modes always emit an IV).
  3. Check the compact string has exactly 5 parts and the 3rd part is non-empty base64url.
  4. If truncation is suspected, re-fetch the token from the issuer instead of repairing it.

Example fix

// before (JWS fed to JWE parser)
Jwt<Header,String> jwe = parser.parse(jwsString);
// after
Jws<Claims> jws = Jwts.parser().verifyWith(key).build().parseSignedClaims(jwsString);
Defensive patterns

Strategy: validation

Validate before calling

String[] parts = jwe.split("\\.", -1);
boolean looksLikeJwe = parts.length == 5 && !parts[2].isEmpty();
if (!looksLikeJwe) throw new IllegalArgumentException("Not a compact JWE (missing IV segment)");

Try / catch

try { parser.parse(token); } catch (MalformedJwtException e) { if (e.getMessage().contains("Initialization Vector")) { /* route to JWS parser or reject */ } }

Prevention

When it happens

Trigger: Parsing a compact JWE that omits the IV segment, has an empty third component, or whose IV text fails to decode to bytes (e.g. a JWS string mistakenly passed to JWE parsing).

Common situations: Passing a JWS (3 or 4 parts, no IV) into a JWE parse path, tokens truncated after the ciphertext start, hand-assembled JWE strings missing the '.' separators.

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


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