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

  1. Pass a properly typed collection: Arrays.asList(...), List.of(...), etc., matching COLLECTION_TYPE.
  2. Check the JWT payload's actual JSON type for that claim and align the value or the registered Parameter type.
  3. 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

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


AI-assisted analysis of jwtk/jjwt@fb71496164 (2026-09-09). Data as JSON: /api/errors/4f1d789b8e1ac936. Report an issue: GitHub.