jwtk/jjwt · error · IllegalArgumentException
Unsupported value type. Expected: ${type.getName()}, found:
Error message
Unsupported value type. Expected: ${type.getName()}, found: ${clazz.getName()} What it means
RequiredTypeConverter.applyFrom checks that a claim value's runtime class is assignable to the configured target type before calling type.cast(o). If not, it throws this IllegalArgumentException naming the expected and actual class names. Null values pass through and return null.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/lang/RequiredTypeConverter.java:44
public RequiredTypeConverter(Class<T> type) {
this.type = Assert.notNull(type, "type argument cannot be null.");
}
@Override
public Object applyTo(T t) {
return t;
}
@Override
public T applyFrom(Object o) {
if (o == null) {
return null;
}
Class<?> clazz = o.getClass();
if (!type.isAssignableFrom(clazz)) {
String msg = "Unsupported value type. Expected: " + type.getName() + ", found: " + clazz.getName();
throw new IllegalArgumentException(msg);
}
return type.cast(o);
}
}View on GitHub (pinned to fb71496164)
Solutions
- Convert the value to the expected type before setting it (e.g. new Date(...) instead of an ISO string).
- Check the class with type.isInstance(value) before assignment to fail fast.
- Fix the source map/serialization so types survive round-trips correctly.
Example fix
// before
jwtBuilder.claim("iat", "2026-09-08T12:00:00Z"); // String, expected Date
// after
jwtBuilder.claim("iat", new Date()); Defensive patterns
Strategy: type-guard
Validate before calling
void checkClaimType(Map<String,Object> claims, Class<?> type) {
for (Map.Entry<String,Object> e : claims.entrySet()) {
if (e.getValue() != null && !type.isInstance(e.getValue())
&& !type.isAssignableFrom(e.getValue().getClass())) {
throw new IllegalArgumentException("Claim '" + e.getKey() + "' expected " + type.getName());
}
}
} Type guard
<T> boolean isOfType(Object o, Class<T> type) {
return o == null || type.isInstance(o);
} Try / catch
try {
converter.applyFrom(value);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Unsupported value type.")) {
// parse the expected/found class names from the message to fix the value
}
throw e;
} Prevention
- Use typed builders/setters instead of raw claim maps
- Verify types after deserializing external JSON into claim maps
- Enable strict typing at serialization boundaries so Dates stay Dates
When it happens
Trigger: Setting a claim value whose Java type does not match the converter's expected type, e.g. putting a String into a claim that must be a Date, or an Integer where a List is required.
Common situations: Copying claims from external JSON maps with loose typing; generic Map<String,Object> building where the wrong value slipped in; serialization round-trips that changed types (e.g. Date became String).
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Invalid claims: + t.getMessage()
- JWK must be a Map<String,?> (JSON Object). Type found: ${typ
- Unexpected Claims JWS.
- Unexpected Claims JWE.
- ${message}Object of class [${objClassName}] must be an insta
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/8532e2bae9212339.
Report an issue: GitHub.