jwtk/jjwt · error · UnsupportedJwtException
Unexpected content JWE.
Error message
Unexpected content JWE.
What it means
SupportedJwtVisitor.onDecryptedContent is the default callback for a JWE (JSON Web Encryption) token that has been authenticated and decrypted, with an arbitrary (byte[]) content payload. The base class throws UnsupportedJwtException because it does not presume to know how to handle decrypted content; applications must override this method. Encountering it means an encrypted content JWE reached a visitor not configured for that type.
Source
Thrown at api/src/main/java/io/jsonwebtoken/SupportedJwtVisitor.java:184
Assert.stateIsInstance(Claims.class, payload, "Unexpected payload data type: ");
return onDecryptedClaims((Jwe<Claims>) jwe);
}
}
/**
* Handles an encountered JWE message that has been authenticated and decrypted, and has byte[] array payload. If
* the JWT creator has set the (optional) {@link Header#getContentType()} value, the application may inspect that
* value to determine how to convert the byte array to the final type as desired.
*
* <p>The default implementation immediately throws an {@link UnsupportedJwtException}; it is expected that
* subclasses will override this method if the application needs to support this type of JWT.</p>
*
* @param jwe the parsed authenticated and decrypted content JWE.
* @return any object to be used after inspecting the JWS, or {@code null} if no return value is necessary.
* @throws UnsupportedJwtException by default, expecting the subclass implementation to override as necessary.
*/
public T onDecryptedContent(Jwe<byte[]> jwe) {
throw new UnsupportedJwtException("Unexpected content JWE.");
}
/**
* Handles an encountered JWE message that has been authenticated and decrypted, and has a {@link Claims} payload.
*
* <p>The default implementation immediately throws an {@link UnsupportedJwtException}; it is expected that
* subclasses will override this method if the application needs to support this type of JWT.</p>
*
* @param jwe the parsed authenticated and decrypted content JWE.
* @return any object to be used after inspecting the JWE, or {@code null} if no return value is necessary.
* @throws UnsupportedJwtException by default, expecting the subclass implementation to override as necessary.
*/
public T onDecryptedClaims(Jwe<Claims> jwe) {
throw new UnsupportedJwtException("Unexpected Claims JWE.");
}
}
View on GitHub (pinned to fb71496164)
Solutions
- Override onDecryptedContent in your SupportedJwtVisitor subclass to handle Jwe<byte[]> and return the desired value.
- If the payload should be Claims, build the JWE with claim-based APIs so onDecryptedClaims is dispatched instead.
- Ensure the parser is configured with the correct decryption key so tokens dispatch to the intended callbacks.
- If content JWEs are unexpected in this flow, reject the token and verify the sender's token type.
Example fix
// before
SupportedJwtVisitor<MyType> visitor = new SupportedJwtVisitor<>() {}; // throws on JWE
// after
SupportedJwtVisitor<MyType> visitor = new SupportedJwtVisitor<>() {
@Override
public MyType onDecryptedContent(Jwe<byte[]> jwe) {
return processDecrypted(jwe.getPayload());
}
}; Defensive patterns
Strategy: try-catch
Validate before calling
// Check the header for enc/alg indicating JWE before parsing
String headerJson = new String(Base64.getUrlDecoder().decode(compact.split("\\.")[0]));
boolean isJwe = headerJson.contains("\"enc\"");
if (isJwe && !visitorSupportsJwe) {
throw new IllegalArgumentException("JWE tokens are not supported by this handler");
} Type guard
boolean isJwe(String token) {
String[] p = token.split("\\.", -1);
return p.length == 5 && new String(Base64.getUrlDecoder().decode(p[0])).contains("\"enc\"");
} Try / catch
try {
result = Jwts.parser().decryptWith(key).build().parse(token);
} catch (UnsupportedJwtException e) {
log.warn("Decrypted content JWE dispatched to a visitor without onDecryptedContent", e);
throw new SecurityException("Content JWE not supported by this visitor", e);
} Prevention
- Override onDecryptedContent if any sender may encrypt raw payloads to you
- Configure decryption keys and required algorithms explicitly on the parser
- Filter or route JWE tokens by their 5-part compact shape before visitor dispatch
- Keep producer/consumer token contracts documented (signed vs encrypted, claims vs content)
When it happens
Trigger: Parsing an encrypted token (JWE, e.g. built with Jwts.builder().encryptWith(key, alg, enc) with non-Claims content) through a parser whose visitor does not override onDecryptedContent — after decryption succeeds, the visitor dispatch throws.
Common situations: Exchanging encrypted opaque payloads between systems; a producer switched from signed JWS to encrypted JWE while the consumer's visitor only handled JWS callbacks; generic decryption pipelines receiving content JWEs without a matching override.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Unexpected Claims JWE.
- Unexpected unsecured Claims JWT.
- Unexpected content JWS.
- Unexpected Claims JWS.
- The '${id}' algorithm requires keys with a length of ${bitsM
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/c85b25136aae80ae.
Report an issue: GitHub.