jwtk/jjwt · error · MalformedJwtException
Compact JWE string represents an encrypted key, but the key
Error message
Compact JWE string represents an encrypted key, but the key is empty.
What it means
During compact JWE parsing, the parser decodes the base64url 'encrypted key' segment and requires it to decode to at least one byte. A present-but-empty encrypted key segment means the JWE structure is corrupt or was generated by a broken producer, so the library throws MalformedJwtException rather than attempting key-wrap decryption.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:510
if (tokenized instanceof TokenizedJwe) {
TokenizedJwe tokenizedJwe = (TokenizedJwe) tokenized;
JweHeader jweHeader = Assert.stateIsInstance(JweHeader.class, header, "Not a JweHeader. ");
// Ensure both an 'alg' and 'enc' header value exists and is supported before spending time/effort
// base64Url-decoding anything:
final AeadAlgorithm encAlg = this.encAlgs.apply(jweHeader);
Assert.stateNotNull(encAlg, "JWE Encryption Algorithm cannot be null.");
@SuppressWarnings("rawtypes") final KeyAlgorithm keyAlg = this.keyAlgs.apply(jweHeader);
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);View on GitHub (pinned to fb71496164)
Solutions
- Regenerate the JWE with a correct producer (ensure KeyAlgorithm writes a non-empty encrypted key for the configured alg).
- Verify the token wasn't truncated or altered in transit; compare against the original issuer output.
- Inspect the 4th component of the compact string and confirm it is valid non-empty base64url for the key-encryption mode.
- If using dir or direct CEK mode, expect no encrypted key segment at all — the string should have an empty 4th part, not whitespace or junk.
Example fix
// before String jwe = header + "." + iv + "." + ciphertext + "." + ""; // empty encrypted key // after String jwe = header + "." + encryptedKey + "." + iv + "." + ciphertext + "." + tag;
Defensive patterns
Strategy: validation
Validate before calling
String[] parts = jwe.split("\\.", -1);
if (parts.length == 5 && !parts[1].isEmpty()) {
byte[] ek = java.util.Base64.getUrlDecoder().decode(pad(parts[1]));
if (ek.length == 0) throw new IllegalArgumentException("empty JWE encrypted key");
} Try / catch
try { parser.parse(jwe); } catch (MalformedJwtException e) { log.warn("Corrupt JWE encrypted key: {}", e.getMessage()); throw new TokenFormatException(e); } Prevention
- Never hand-assemble or hand-edit compact JWE strings.
- Validate token structure (5 dot-separated base64url segments) at system boundaries.
- Ensure token producers use JJWT's serializer rather than custom string building.
- Guard against truncation by validating token length/checksums at transport layers.
When it happens
Trigger: Parsing a compact JWE whose fourth dot-separated component is non-empty base64url text that decodes to zero bytes (e.g. via JwtParser.parseClaimsJws/parse on a JWE string).
Common situations: Truncated or hand-edited JWE strings, buggy custom JWE builders that emit an empty key segment, round-tripping tokens through systems that mangle base64url padding.
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 Initialization Ve
- Compact JWE strings must always contain an AAD Authenticatio
- Unexpected content JWE.
- Unexpected Claims JWE.
- Illegal ${name} character: '${c}'
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/6d28845421a4eb96.
Report an issue: GitHub.