jwtk/jjwt · error · ClassCastException
Cannot cast ${value.getClass().getName()} to ${IDIOMATIC_TYP
Error message
Cannot cast ${value.getClass().getName()} to ${IDIOMATIC_TYPE.getName()} What it means
DefaultParameter.cast, for non-collection parameters, checks the value is an instance of the declared type (IDIOMATIC_TYPE) and throws a ClassCastException otherwise. This is the plain scalar-path type guard applied to every typed header/claim parameter.
Source
Thrown at impl/src/main/java/io/jsonwebtoken/impl/lang/DefaultParameter.java:88
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();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Parameter) {View on GitHub (pinned to fb71496164)
Solutions
- Convert the value to the declared type before assignment (String.valueOf(x), Long.parseLong(s), etc.).
- Inspect the token's raw JSON to see the actual type and adjust the value or the parameter registration.
- When reading, cast defensively via instanceof checks before using the claim value.
Example fix
// before
Object exp = claims.get("exp"); // Integer
Long l = (Long) exp; // ClassCastException via parameter cast
// after
Object exp = claims.get("exp");
Long l = (exp instanceof Number) ? ((Number) exp).longValue() : Long.parseLong(exp.toString()); Defensive patterns
Strategy: type-guard
Validate before calling
if (value != null && !expectedType.isInstance(value)) {
value = convert(value, expectedType); // String.valueOf, Long.parseLong, ...
} Type guard
static <T> T asType(Object v, Class<T> t) {
return t.isInstance(v) ? t.cast(v) : null;
} Try / catch
try {
String s = (String) claims.get("sub");
} catch (ClassCastException e) {
s = String.valueOf(claims.get("sub"));
} Prevention
- Use instanceof checks instead of blind casts on claim values
- Read claim values as Object and convert explicitly
- Compare your parameter registrations with the actual token JSON types
When it happens
Trigger: Setting a claim/header value whose runtime type differs from the registered parameter type, e.g. an Integer where a String is expected, or a String where a Date/Long parameter expects a number; also triggered during JWT deserialization when the JSON type doesn't match the schema.
Common situations: External issuers emitting numeric claims the library declares as strings; copying claims between tokens with different schemas; using raw/untyped builders that bypass generics.
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 ${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/ea37e3a2c9f0fd6d.
Report an issue: GitHub.