apache/flink · error · RuntimeException

Cannot instantiate class.

Error message

Cannot instantiate class.

What it means

PojoSerializer.createInstance() attempts to build a fresh POJO via reflection (no-arg constructor) and then populate each field with a default instance from its field serializer. This RuntimeException is the outer catch that wraps ANY failure during that two-step process — either raw instantiation failed or field initialization failed. The wrapped cause (getCause()) holds the specific reason (NoSuchMethodException, InvocationTargetException, IllegalAccessException, etc.).

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/PojoSerializer.java:225

        if (!stateful) {
            // as a small memory optimization, we can share the same object between instances
            duplicateSerializers = serializers;
        }
        return (TypeSerializer<Object>[]) duplicateSerializers;
    }

    @Override
    public T createInstance() {
        if (clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()) || isRecord()) {
            return null;
        }
        try {
            T t = instantiateRaw();
            initializeFields(t);
            return t;
        } catch (Exception e) {
            throw new RuntimeException("Cannot instantiate class.", e);
        }
    }

    private T instantiateRaw() {
        try {
            if (constructor == null) {
                constructor = clazz.getDeclaredConstructor();
                constructor.setAccessible(true);
            }
            return constructor.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Cannot instantiate class.", e);
        }
    }

    protected void initializeFields(T t) {
        for (int i = 0; i < numFields; i++) {
            if (fields[i] != null) {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Inspect the wrapped cause via exception.getCause() — it distinguishes 'no no-arg constructor' from 'constructor threw' from 'field init failed'.
  2. Add a public no-arg constructor to the POJO class (or at minimum an accessible private one — setAccessible is called).
  3. If the POJO genuinely cannot have a no-arg constructor, register a custom TypeSerializer or TypeSerializerSnapshot, or annotate the type so Flink falls back to Kryo/Avro serialization.
  4. Ensure the exact same JAR (including POJO class) is deployed on all TaskManagers and the JobManager.
  5. If the class was refactored/renamed between job versions, implement a TypeSerializerSnapshot migration or reset state from a clean savepoint.

Example fix

// before — POJO with no no-arg constructor
public class MyEvent {
    private String id;
    public MyEvent(String id) { this.id = id; }
}

// after — add a no-arg constructor for the serializer
public class MyEvent {
    private String id;
    public MyEvent() { this.id = ""; }  // serializer calls this
    public MyEvent(String id) { this.id = id; }
}
Defensive patterns

Strategy: validation

Validate before calling

// Before using a POJO type, verify it has an accessible no-arg constructor
import java.lang.reflect.Constructor;

public static boolean hasNoArgConstructor(Class<?> clazz) {
    try {
        Constructor<?> c = clazz.getDeclaredConstructor();
        c.setAccessible(true);
        return true;
    } catch (NoSuchMethodException | SecurityException e) {
        return false;
    }
}

// Usage in a test or pipeline setup
if (!hasNoArgConstructor(MyPojo.class)) {
    throw new IllegalStateException(
        "POJO " + MyPojo.class.getName() + " needs a no-arg constructor for PojoSerializer");
}

Try / catch

try {
    T instance = pojoSerializer.createInstance();
} catch (RuntimeException e) {
    Throwable cause = e.getCause();
    log.error("PojoSerializer.createInstance failed for {}: {}",
        pojoSerializer.getClass().getName(), cause != null ? cause : e);
    // cause is typically NoSuchMethodException, InvocationTargetException,
    // or IllegalAccessException — handle accordingly
    throw e;
}

Prevention

When it happens

Trigger: The Flink runtime calls TypeSerializer.createInstance() during keyed-state restoration, spill/reload of POJO data, or when the sort/hash infrastructure needs a scratch instance. The exception fires when the POJO class cannot be reflectively constructed or when a field serializer cannot produce a default value for one of the POJO's fields.

Common situations: POJO class has only parameterized constructors and no no-arg constructor; POJO class was relocated or shaded so the loaded class differs from the one the serializer snapshot expects; a nested POJO field type itself lacks a no-arg constructor; the POJO class is not on the TaskManager classpath after a JAR change; the constructor exists but throws internally (e.g., requires a dependency injected at construction time).

Related errors


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