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

  1. Make the configured class implement/extend the exact required interface (same package and same classloader copy)
  2. Eliminate duplicate copies of the interface jar (parent vs user classloader) so isAssignableFrom compares the same Class object
  3. 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

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


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