jwtk/jjwt · error · UnsupportedJwtException

Unexpected content JWS.

Error message

Unexpected content JWS.

What it means

SupportedJwtVisitor.onVerifiedContent is the default callback for a JWS (cryptographically verified token) whose payload is arbitrary content (byte[], not Claims JSON). The base implementation throws UnsupportedJwtException because the library assumes a specific visitor subclass; applications handling raw-payload JWSs must override this method. It indicates the token type received does not match what the visitor is configured to handle.

Source

Thrown at api/src/main/java/io/jsonwebtoken/SupportedJwtVisitor.java:129

            Assert.stateIsInstance(Claims.class, payload, "Unexpected payload data type: ");
            return onVerifiedClaims((Jws<Claims>) jws);
        }
    }

    /**
     * Handles an encountered JWS message that has been cryptographically verified/authenticated and has
     * a 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 jws the parsed verified/authenticated JWS.
     * @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 onVerifiedContent(Jws<byte[]> jws) {
        throw new UnsupportedJwtException("Unexpected content JWS.");
    }

    /**
     * Handles an encountered JWS message that has been cryptographically verified/authenticated 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 jws the parsed signed (and verified) Claims JWS
     * @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 onVerifiedClaims(Jws<Claims> jws) {
        throw new UnsupportedJwtException("Unexpected Claims JWS.");
    }

    /**

View on GitHub (pinned to fb71496164)

Solutions

  1. Override onVerifiedContent in your SupportedJwtVisitor subclass to process Jws<byte[]> and return the desired value.
  2. If the payload should be Claims, change the producer to use claim-based builder APIs (Jwts.builder().claims()...) so onVerifiedClaims is dispatched instead.
  3. If content JWSs are not expected, reject the token and validate the producer/endpoint sending it.
  4. Use the matching parse API (e.g. parseContentJws if available) so the intended callback is invoked.

Example fix

// before
SupportedJwtVisitor<MyType> visitor = new SupportedJwtVisitor<>() {}; // default throws
// after
SupportedJwtVisitor<MyType> visitor = new SupportedJwtVisitor<>() {
    @Override
    public MyType onVerifiedContent(Jws<byte[]> jws) {
        byte[] payload = jws.getPayload();
        return processSignedContent(payload);
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Decode header before parsing to learn the payload kind
String headerJson = new String(Base64.getUrlDecoder().decode(compact.split("\\.")[0]));
boolean isJwsWithClaims = headerJson.contains("\"JWT\""); // typ claim hint
if (!isJwsWithClaims && !visitorSupportsContentJws) {
    throw new IllegalArgumentException("Content JWS not supported by this handler");
}

Type guard

boolean isSignedContentJws(String token) {
    String[] p = token.split("\\.", -1);
    return p.length == 3 && !p[2].isEmpty(); // signed (has signature), payload type confirmed at parse time
}

Try / catch

try {
    result = Jwts.parser().verifyWith(key).build().parse(token);
} catch (UnsupportedJwtException e) {
    log.warn("Received a content JWS the visitor does not handle", e);
    throw new SecurityException("Unsupported JWS payload type", e);
}

Prevention

When it happens

Trigger: Parsing a signed compact token whose payload is not a Claims JSON object (e.g. arbitrary string/binary content) via a parser whose visitor does not override onVerifiedContent. E.g. calling parser.parse() on a JWS built with Jwts.builder().setContent(bytes, sigAlg, key).

Common situations: Exchanging opaque signed payloads between services; a developer expected Claims but the producer sent raw content; mixing parseClaimsJws with content-JWS tokens; generic token-handling middleware that lacks an onVerifiedContent 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/2f3118b59e616295. Report an issue: GitHub.