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

  1. Override onDecryptedContent in your SupportedJwtVisitor subclass to handle Jwe<byte[]> and return the desired value.
  2. If the payload should be Claims, build the JWE with claim-based APIs so onDecryptedClaims is dispatched instead.
  3. Ensure the parser is configured with the correct decryption key so tokens dispatch to the intended callbacks.
  4. 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

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


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