jwtk/jjwt · error · MalformedJwtException
Compact JWE strings MUST always contain a payload (ciphertex
Error message
Compact JWE strings MUST always contain a payload (ciphertext).
What it means
Unlike JWS payloads, which may legally be empty, a compact JWE must always contain ciphertext in its payload segment. jjwt throws MalformedJwtException when a TokenizedJwe has an empty payload, because encryption of nothing cannot be represented in compact serialization here.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtParser.java:487
if (Strings.hasText(payloadToken)) {
// we need to verify what was in the token, otherwise it'd be a security issue if we ignored it
// and assumed the (likely safe) unencodedPayload value instead:
payload = new Payload(payloadToken, header.getContentType());
} else {
//no payload token (a detached payload), so we need to ensure that they've specified the payload value:
if (unencodedPayload.isEmpty()) {
String msg = String.format(B64_MISSING_PAYLOAD, header);
throw new SignatureException(msg);
}
// otherwise, use the specified payload:
payload = unencodedPayload;
}
}
if (tokenized instanceof TokenizedJwe && payload.isEmpty()) {
// Only JWS payload can be empty per https://github.com/jwtk/jjwt/pull/540
String msg = "Compact JWE strings MUST always contain a payload (ciphertext).";
throw new MalformedJwtException(msg);
}
byte[] iv = null;
byte[] digest = null; // either JWE AEAD tag or JWS signature after Base64Url-decoding
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();View on GitHub (pinned to fb71496164)
Solutions
- Re-issue the JWE with non-empty content (an empty claims map still produces valid ciphertext).
- Verify the compact string has all five non-empty JWE segments before parsing.
- Fix the producer so it never serializes an empty ciphertext segment; if there is truly nothing to encrypt, use a signed JWS instead.
- Check for transport truncation if the token appears cut off.
Example fix
// before: JWE with empty ciphertext
String jwe = h + "." + k + "." + iv + "." + "" + "." + tag;
// after: always encrypt something (e.g. empty claims map)
String jwe = Jwts.builder().claims(Collections.emptyMap())
.encryptWith(key, Jwts.KEY.A128KW, Jwts.ENC.A128GCM).compact(); Defensive patterns
Strategy: validation
Validate before calling
String[] parts = jwe.split("\\.", -1);
if (parts.length == 5 && parts[3].isEmpty()) throw new IllegalArgumentException("JWE ciphertext segment is empty"); Try / catch
try { return parser.parse(jwe); }
catch (io.jsonwebtoken.MalformedJwtException e) { throw new InvalidTokenException("JWE payload empty", e); } Prevention
- Never serialize empty ciphertext; encrypt at least an empty claims map
- Use Jwts.builder().encryptWith(...) instead of manual serialization
- Validate all five JWE segments are non-empty before parsing
- Use a signed JWS if you have no content to encrypt
When it happens
Trigger: Calling parse() on a JWE compact string whose fourth segment (ciphertext) is empty — e.g. header.key.iv..tag or a truncated string.
Common situations: Attempting to 'encrypt' an empty body and producing a malformed token; truncation or corruption removing the ciphertext segment; copying 4 of 5 segments; custom serializers mishandling empty claims maps.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Encrypted JWTs must have either 'claims' or non-empty 'conte
- JWEs do not support key management alg header value 'none' p
- The JWE header references key management algorithm '%s' but
- Unexpected content JWE.
- Unexpected Claims JWE.
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/6cb76035cdd8cc8b.
Report an issue: GitHub.