apache/flink · error · InvalidTypesException

Generic type '{}' or a subclass of it expected but was '{}'.

Error message

Generic type '{}' or a subclass of it expected but was '{}'.

What it means

Thrown by TypeExtractor.validateInfo when a GenericTypeInfo is expected but the reflected type's class is not assignable to (i.e., is not the same class or a subclass of) the GenericTypeInfo's type class. This means the extractor expected a specific generic type or its subclass but found an incompatible class.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java:1703

                }
                // check enum type contents
                if (!(typeInfo.getTypeClass() == type)) {
                    throw new InvalidTypesException(
                            "Enum type '"
                                    + typeInfo.getTypeClass().getCanonicalName()
                                    + "' expected but was '"
                                    + typeToClass(type).getCanonicalName()
                                    + "'.");
                }
            }
            // check for generic object
            else if (typeInfo instanceof GenericTypeInfo<?>) {
                Class<?> clazz = null;
                if (!(isClassType(type)
                        && (clazz = typeToClass(type))
                                .isAssignableFrom(
                                        ((GenericTypeInfo<?>) typeInfo).getTypeClass()))) {
                    throw new InvalidTypesException(
                            "Generic type '"
                                    + ((GenericTypeInfo<?>) typeInfo)
                                            .getTypeClass()
                                            .getCanonicalName()
                                    + "' or a subclass of it expected but was '"
                                    + clazz.getCanonicalName()
                                    + "'.");
                }
            }
            // check for Writable
            else {
                validateIfWritable(typeInfo, type);
            }
        } else {
            type = materializeTypeVariable(typeHierarchy, (TypeVariable<?>) type);
            if (!(type instanceof TypeVariable)) {
                validateInfo(typeHierarchy, type, typeInfo);
            }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Ensure the actual class is the same as or a subclass of the declared GenericTypeInfo type class.
  2. Provide explicit TypeInformation via .returns(TypeInformation.of(ExpectedClass.class)).
  3. If the class hierarchy is correct but erasure is the issue, create a concrete non-generic subclass to preserve type info.
  4. Verify that the generic type parameter in the function signature has the correct bound.

Example fix

// before
public class MyFunction<T> extends RichMapFunction<T, OtherClass> { ... }
// T resolves to Object due to erasure
// after
public class MyStringFunction extends RichMapFunction<String, OtherClass> { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Check that the actual class is a subclass of the expected generic type
Class<?> expectedClass = ((GenericTypeInfo<?>) typeInfo).getTypeClass();
Class<?> actualClass = typeToClass(type);
if (!expectedClass.isAssignableFrom(actualClass)) {
    // provide correct GenericTypeInfo or concrete TypeInformation
    ti = TypeInformation.of(actualClass);
}

Type guard

static boolean genericTypesCompatible(GenericTypeInfo<?> expected, Type actual) {
    return isClassType(actual)
        && expected.getTypeClass().isAssignableFrom(typeToClass(actual));
}

Try / catch

try {
    validateInfo(hierarchy, type, genericTypeInfo);
} catch (InvalidTypesException e) {
    ti = TypeInformation.of(typeToClass(type));
}

Prevention

When it happens

Trigger: Called during validateInfo when TypeInformation is a GenericTypeInfo and either the type is not a ClassType, or the resolved class is not isAssignableFrom the expected type class. Occurs when the actual class is unrelated to the declared generic type (not a subclass).

Common situations: Using a completely unrelated class where a specific generic type was expected. Type erasure resolving to Object or an unrelated class in deeply generic hierarchies. Generic base classes where the type parameter is unbounded and resolves to an unexpected class.

Related errors


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