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
- Ensure you are parsing the right token type: JWS strings have no IV; use the JWS API for them.
- Regenerate the JWE with a valid producer so the IV segment is populated (all standard JWE enc modes always emit an IV).
- Check the compact string has exactly 5 parts and the 3rd part is non-empty base64url.
- 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
- Distinguish JWS vs JWE token types before choosing the parser API.
- Always confirm the 3rd segment of a JWE is non-empty base64url.
- Avoid manual string manipulation of tokens; pass the original string end-to-end.
- Test token round-trips (issue -> parse) in CI to catch producer regressions.
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
- Compact JWE strings must always contain an AAD Authenticatio
- Compact JWE string represents an encrypted key, but the key
- Ciphertext decryption failed: Authentication tag verificatio
- Unexpected content JWE.
- Unexpected Claims JWE.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/f65735a25de897e2.
Report an issue: GitHub.