apache/flink · error · InvalidTypesException
Writable type '{}' expected but was '{}'.
Error message
Writable type '{}' expected but was '{}'. What it means
Thrown by TypeExtractor.validateIfWritable when a WritableTypeInfo is expected, the type is a valid Hadoop Writable, but the expected Writable type class differs from the actual class found by reflection. This indicates a mismatch between two specific Writable types.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java:2503
// try to load the writable type info
Class<?> writableTypeInfoClass =
Class.forName(
HADOOP_WRITABLE_TYPEINFO_CLASS,
false,
typeInfo.getClass().getClassLoader());
if (writableTypeInfoClass.isAssignableFrom(typeInfo.getClass())) {
// this is actually a writable type info
// check if the type is a writable
if (!(type instanceof Class && isHadoopWritable((Class<?>) type))) {
throw new InvalidTypesException(HADOOP_WRITABLE_CLASS + " type expected.");
}
// check writable type contents
Class<?> clazz = (Class<?>) type;
if (typeInfo.getTypeClass() != clazz) {
throw new InvalidTypesException(
"Writable type '"
+ typeInfo.getTypeClass().getCanonicalName()
+ "' expected but was '"
+ clazz.getCanonicalName()
+ "'.");
}
}
} catch (ClassNotFoundException e) {
// class not present at all, so cannot be that type info
// ignore
}
}
}
View on GitHub (pinned to 2f3c205e92)
Solutions
- Align the declared WritableTypeInfo with the actual Writable class used at runtime.
- Provide the correct explicit TypeInformation via .returns(WritableTypeInfo.of(ActualWritableClass.class)).
- Check for accidental Writable type substitution (e.g., Text vs BytesWritable).
- Update type hints after refactoring Writable types.
Example fix
// before .returns(WritableTypeInfo.of(IntWritable.class)) // actual is LongWritable // after .returns(WritableTypeInfo.of(LongWritable.class))
Defensive patterns
Strategy: validation
Validate before calling
// Check that the expected Writable class matches the actual
Class<?> expectedWritable = typeInfo.getTypeClass();
Class<?> actualWritable = (Class<?>) type;
if (expectedWritable != actualWritable) {
// align WritableTypeInfo with actual class
ti = WritableTypeInfo.of(actualWritable);
} Type guard
static boolean writableClassesMatch(TypeInformation<?> expected, Class<?> actual) {
return expected.getTypeClass() == actual;
} Try / catch
try {
validateIfWritable(typeInfo, type);
} catch (InvalidTypesException e) {
ti = WritableTypeInfo.of((Class<?>) type);
} Prevention
- Align declared WritableTypeInfo with the actual Writable class.
- Avoid substituting one Writable type for another.
- Update type hints after refactoring Writable types.
When it happens
Trigger: Called during validateIfWritable after confirming the type is a Writable, but typeInfo.getTypeClass() != clazz (the actual class). Occurs when the declared WritableTypeInfo references one Writable class but the reflected type argument resolves to a different Writable class.
Common situations: Declaring a WritableTypeInfo for IntWritable but the function returns LongWritable. Generic UDFs where different Writable types appear in declared vs actual positions. Using a custom Writable subclass where the parent Writable was expected. Refactoring Writable type usages without updating type hints.
Related errors
- org.apache.hadoop.io.Writable type expected.
- InputSplit must implement Writable interface.
- Cannot create Comparator for {typeClass.getCanonicalName()}.
- The given class is no subclass of {Writable.class.getName()}
- POJO type '{}' expected but was '{}'.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/0be113305c8c28b4.
Report an issue: GitHub.