apache/flink · error · RuntimeException
The class '{}' is not a subclass of '{}' as is required.
Error message
The class '{}' is not a subclass of '{}' as is required. What it means
InstantiationUtil.instantiate(clazz, castTo) checks castTo.isAssignableFrom(clazz) before calling newInstance and throws RuntimeException('The class X is not a subclass of Y as is required.') on mismatch. This is an explicit early type check so the failure is a clear message at instantiation time instead of a ClassCastException far away at first use.
Source
Thrown at flink-core/src/main/java/org/apache/flink/util/InstantiationUtil.java:283
/**
* Creates a new instance of the given class.
*
* @param <T> The generic type of the class.
* @param clazz The class to instantiate.
* @param castTo Optional parameter, specifying the class that the given class must be a
* subclass off. This argument is added to prevent class cast exceptions occurring later.
* @return An instance of the given class.
* @throws RuntimeException Thrown, if the class could not be instantiated. The exception
* contains a detailed message about the reason why the instantiation failed.
*/
public static <T> T instantiate(Class<T> clazz, Class<? super T> castTo) {
if (clazz == null) {
throw new NullPointerException();
}
// check if the class is a subclass, if the check is required
if (castTo != null && !castTo.isAssignableFrom(clazz)) {
throw new RuntimeException(
"The class '"
+ clazz.getName()
+ "' is not a subclass of '"
+ castTo.getName()
+ "' as is required.");
}
return instantiate(clazz);
}
/**
* Creates a new instance of the given class.
*
* @param <T> The generic type of the class.
* @param clazz The class to instantiate.
* @return An instance of the given class.
* @throws RuntimeException Thrown, if the class could not be instantiated. The exception
* contains a detailed message about the reason why the instantiation failed.View on GitHub (pinned to 2f3c205e92)
Solutions
- Make the configured class implement/extend the exact required interface (same package and same classloader copy)
- Eliminate duplicate copies of the interface jar (parent vs user classloader) so isAssignableFrom compares the same Class object
- After shading/relocation, verify the interface FQCN in your implementation matches the one the framework loads
Example fix
// before
public class MySink implements SinkFunction<String> { ... } // API now requires Sink<String>
InstantiationUtil.instantiate(clazz, Sink.class);
// after
public class MySink implements org.apache.flink.api.connector.sink2.Sink<String> { ... } Defensive patterns
Strategy: validation
Validate before calling
if (!requiredType.isAssignableFrom(clazz)) {
throw new IllegalArgumentException(clazz + " must implement " + requiredType.getName());
} Prevention
- Compile plugin classes against the exact framework artifact version deployed
- Remove duplicate copies of interface jars across loaders
When it happens
Trigger: Passing a class that does not implement/extend the expected supertype — e.g. configuring a class named for interface A where the API requires subtype B, or two same-named classes from different loaders/packages after relocation.
Common situations: Plugin SPI-style loading where the configured implementation implements a different (or relocated duplicate) interface version; version upgrades that changed the required base type; copy-paste of a class name between incompatible extension points.
Related errors
- No lambda method found.
- Could not extract lambda method out of function: {} - {}
- Could not find record canonical constructor
- Could not access the MODEL$ field of avro record
- Cannot deserialize and unwrap accumulators properly.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/6af4d90019d71be4.
Report an issue: GitHub.