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()}>: At least one element is not an instance of ${IDIOMATIC_TYPE.getName()} What it means
DefaultParameter.cast, after confirming the value is the expected collection type, checks that its elements are instances of the declared element type (IDIOMATIC_TYPE). If at least one element is of the wrong type, a ClassCastException is thrown noting 'At least one element is not an instance of ...'. This only inspects the first element, so it detects a bad first element specifically.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/lang/DefaultParameter.java:83
@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;
}
@Override
public boolean isSecret() {
return SECRET;
}
@Override
public int hashCode() {
return this.ID.hashCode();View on GitHub (pinned to fb71496164)
Solutions
- Ensure every element matches the declared element type before assignment.
- Convert elements explicitly (map each to String/Long as required) before setting the claim.
- If the JWT payload genuinely contains mixed types, change the registered parameter element type to a common supertype (e.g. Object).
Example fix
// before
List<Object> roles = Arrays.asList("admin", 42);
jwt.claim("roles", roles);
// after
List<String> roles = Arrays.asList("admin", "42");
jwt.claim("roles", roles); Defensive patterns
Strategy: type-guard
Validate before calling
boolean ok = value instanceof Collection
&& ((Collection<?>) value).stream().allMatch(expectedElemType::isInstance);
if (!ok) { /* convert or reject */ } Type guard
static <T> boolean allInstanceOf(Collection<?> c, Class<T> t) {
return c.stream().allMatch(t::isInstance);
} Try / catch
try {
param.cast(collection);
} catch (ClassCastException e) {
// inspect elements, convert or reject the collection
} Prevention
- Never build claim collections from raw JSON arrays without validating element types
- Map elements to the declared type explicitly before assignment
- Reject or sanitize heterogeneous arrays at the ingestion boundary
When it happens
Trigger: Assigning a Collection whose first element is not of the declared element type, e.g. a List<Object> containing an Integer into a Collection<String> parameter, or a deserialized heterogeneous JSON array.
Common situations: JSON arrays with mixed types (["a", 1]); generics erasure letting List<Integer> slip into a List<String> slot; builders taking raw Collection types.
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 ${COLLECTION_TY
- Cannot cast ${value.getClass().getName()} to ${IDIOMATIC_TYP
- ${message}Object of class [${objClassName}] must be an insta
- ${message}${subType} is not assignable to ${superType}
- Source is not an array:
AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09).
Data as JSON: /api/errors/f9ec44e2e92d58f9.
Report an issue: GitHub.