apache/flink · error · IllegalArgumentException

Cannot convert type to class

Error message

Cannot convert type to class

What it means

Thrown by TypeExtractionUtils.typeToClass when the given Type is neither a Class nor a ParameterizedType. This covers TypeVariable (unresolved generic type variables like T), GenericArrayType, or WildcardType. The method only knows how to extract a raw Class from Class or ParameterizedType; all other Type subtypes are rejected.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractionUtils.java:285

    public static List<Method> getAllDeclaredMethods(Class<?> clazz) {
        List<Method> result = new ArrayList<>();
        while (clazz != null) {
            Method[] methods = clazz.getDeclaredMethods();
            Collections.addAll(result, methods);
            clazz = clazz.getSuperclass();
        }
        return result;
    }

    /** Convert ParameterizedType or Class to a Class. */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> typeToClass(Type t) {
        if (t instanceof Class) {
            return (Class<T>) t;
        } else if (t instanceof ParameterizedType) {
            return ((Class<T>) ((ParameterizedType) t).getRawType());
        }
        throw new IllegalArgumentException("Cannot convert type to class");
    }

    /**
     * Checks if a type can be converted to a Class. This is true for ParameterizedType and Class.
     */
    public static boolean isClassType(Type t) {
        return t instanceof Class<?> || t instanceof ParameterizedType;
    }

    /** Checks whether two types are type variables describing the same. */
    public static boolean sameTypeVars(Type t1, Type t2) {
        return t1 instanceof TypeVariable
                && t2 instanceof TypeVariable
                && ((TypeVariable<?>) t1).getName().equals(((TypeVariable<?>) t2).getName())
                && ((TypeVariable<?>) t1)
                        .getGenericDeclaration()
                        .equals(((TypeVariable<?>) t2).getGenericDeclaration());
    }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Bind all generic type parameters to concrete types (e.g. class MyMapper implements MapFunction<String, Integer>).
  2. Use an anonymous class with explicit type arguments.
  3. Specify the type information explicitly with .returns(TypeInformation.of(...)).
  4. Implement ResultTypeQueryable to bypass automatic extraction.

Example fix

// before
public class MyMapper<T> implements MapFunction<T, String> {
    public String map(T value) { return value.toString(); }
}
// after
public class MyMapper implements MapFunction<String, String> {
    public String map(String value) { return value.toUpperCase(); }
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(t instanceof Class) && !(t instanceof ParameterizedType)) {
    throw new IllegalArgumentException(
        "Cannot convert type " + t + " to Class; must be Class or ParameterizedType");
}

Type guard

static boolean isClassType(Type t) {
    return t instanceof Class<?> || t instanceof ParameterizedType;
}

Prevention

When it happens

Trigger: Type extraction encounters an unresolved TypeVariable (T) because the generic was never bound to a concrete type through the hierarchy. A GenericArrayType (T[]) is passed where a simple type was expected. The type hierarchy has a gap where a type variable is not resolved.

Common situations: Function generics not fully resolved (e.g. class MyMapper<T> implements MapFunction<T, String> where T is never bound). Using arrays of generic types. Deep generic inheritance chains where type variables are not resolved at some level.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/38a0e5ec00e9aae0. Report an issue: GitHub.