jwtk/jjwt · error · ClassCastException
Cannot cast ${value.getClass().getName()} to ${COLLECTION_TY
Error message
Cannot cast ${value.getClass().getName()} to ${COLLECTION_TYPE.getName()}<${IDIOMATIC_TYPE.getName()}> What it means
DefaultParameter.cast validates a value assigned to a typed JWT header/claim parameter. When the parameter is a collection type and the value is not an instance of the expected collection class (e.g. not a List/Set), a ClassCastException is thrown describing the actual vs expected types. This guards Java's type-erased collections at runtime.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/lang/DefaultParameter.java:74
if (value == null) {
return true;
}
if (COLLECTION_TYPE != null && COLLECTION_TYPE.isInstance(value)) {
Collection<? extends T> c = COLLECTION_TYPE.cast(value);
return c.isEmpty() || IDIOMATIC_TYPE.isInstance(c.iterator().next());
}
return IDIOMATIC_TYPE.isInstance(value);
}
@SuppressWarnings("unchecked")
@Override
public T cast(Object value) {
if (value != null) {
if (COLLECTION_TYPE != null) { // parameter represents a collection, ensure it and its elements are the expected type:
if (!COLLECTION_TYPE.isInstance(value)) {
String msg = "Cannot cast " + value.getClass().getName() + " to " +
COLLECTION_TYPE.getName() + "<" + IDIOMATIC_TYPE.getName() + ">";
throw new ClassCastException(msg);
}
Collection<?> c = COLLECTION_TYPE.cast(value);
if (!c.isEmpty()) {
Object element = c.iterator().next();
if (!IDIOMATIC_TYPE.isInstance(element)) {
String msg = "Cannot cast " + value.getClass().getName() + " to " +
COLLECTION_TYPE.getName() + "<" + IDIOMATIC_TYPE.getName() + ">: At least one " +
"element is not an instance of " + IDIOMATIC_TYPE.getName();
throw new ClassCastException(msg);
}
}
} else if (!IDIOMATIC_TYPE.isInstance(value)) {
String msg = "Cannot cast " + value.getClass().getName() + " to " + IDIOMATIC_TYPE.getName();
throw new ClassCastException(msg);
}
}
return (T) value;
}View on GitHub (pinned to fb71496164)
Solutions
- Pass a properly typed collection: Arrays.asList(...), List.of(...), etc., matching COLLECTION_TYPE.
- Check the JWT payload's actual JSON type for that claim and align the value or the registered Parameter type.
- Wrap assignment in a conversion step that normalizes single values into a one-element list.
Example fix
// before
jwt.claim("roles", "admin"); // parameter expects Collection
// after
jwt.claim("roles", java.util.Collections.singletonList("admin")); Defensive patterns
Strategy: type-guard
Validate before calling
if (!(value instanceof List) && !(value instanceof Set)) {
value = Collections.singletonList(value);
} Type guard
static boolean isCollectionOf(Object v, Class<?> collType, Class<?> elemType) {
return collType.isInstance(v)
&& ((Collection<?>) v).stream().allMatch(elemType::isInstance);
} Try / catch
try {
param.cast(value);
} catch (ClassCastException e) {
// coerce to expected collection type before retrying
} Prevention
- Use typed generics (List<String>) at call sites, never raw Collections
- Normalize scalar-or-array claim input into a list before assignment
- Check external issuers' claim shapes against your parameter schema
When it happens
Trigger: Putting a non-collection value (String, Map, array) into a claim whose parameter is declared as Collection<SomeType>, or deserializing a JWT whose claim JSON type differs from the declared parameter type.
Common situations: A claim normally a List<String> arriving as a single String from an external issuer; custom claim builders passing wrong types; JSON payloads where arrays got collapsed to scalars.
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
- Cannot cast ${value.getClass().getName()} to ${IDIOMATIC_TYP
- Cannot cast ${value.getClass().getName()} to ${COLLECTION_TY
- Cannot create Date from object of type ${v.getClass().getNam
- ${message}Object of class [${objClassName}] must be an insta
- ${message}${subType} is not assignable to ${superType}
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/4f1d789b8e1ac936.
Report an issue: GitHub.