apache/flink · error · FlinkRuntimeException

The implementation of AbstractDeserializationSchema is using

Error message

The implementation of AbstractDeserializationSchema is using a generic variable. This is not supported, because due to Java's generic type erasure, it will not be possible to determine the full type at runtime. For generic implementations, please pass the TypeInformation or type class explicitly to the constructor.

What it means

Thrown by the no-arg constructor of AbstractDeserializationSchema when TypeExtractor cannot resolve the concrete type parameter at runtime due to Java generic type erasure. The schema must know its produced TypeInformation to build serializers; an unbound generic variable (e.g. <T>) makes that impossible. The fix is to supply the type explicitly via the alternate constructor that accepts a Class or TypeInformation.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/serialization/AbstractDeserializationSchema.java:107

     * <p>This constructor is usable whenever the DeserializationSchema concretely defines its type,
     * without generic variables:
     *
     * <pre>{@code
     * public class MyDeserializationSchema extends AbstractDeserializationSchema<MyType> {
     *
     *     public MyType deserialize(byte[] message) throws IOException {
     *         ...
     *     }
     * }
     * }</pre>
     */
    protected AbstractDeserializationSchema() {
        try {
            this.type =
                    TypeExtractor.createTypeInfo(
                            AbstractDeserializationSchema.class, getClass(), 0, null, null);
        } catch (InvalidTypesException e) {
            throw new FlinkRuntimeException(
                    "The implementation of AbstractDeserializationSchema is using a generic variable. "
                            + "This is not supported, because due to Java's generic type erasure, it will not be possible to "
                            + "determine the full type at runtime. For generic implementations, please pass the TypeInformation "
                            + "or type class explicitly to the constructor.",
                    e);
        }
    }

    /**
     * Creates an AbstractDeserializationSchema that returns the TypeInformation indicated by the
     * given class. This constructor is only necessary when creating a generic implementation, see
     * {@link AbstractDeserializationSchema Generic Use}.
     *
     * <p>This constructor may fail if the class is generic. In that case, please use the
     * constructor that accepts a {@link #AbstractDeserializationSchema(TypeHint) TypeHint}, or a
     * {@link #AbstractDeserializationSchema(TypeInformation) TypeInformation}.
     *
     * @param type The class of the produced type.

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. If the class is concrete, bind the type parameter directly: class MySchema extends AbstractDeserializationSchema<MyType> and keep the no-arg constructor.
  2. If the class must be generic, accept the type in the constructor and forward it: public MySchema(Class<T> type) { super(type); } or public MySchema(TypeInformation<T> typeInfo) { super(typeInfo); }.
  3. If you cannot change the class hierarchy, create a separate non-generic subclass per concrete type.

Example fix

// before
public class MyGenericSchema<T> extends AbstractDeserializationSchema<T> {
    public MyGenericSchema(Class<T> type) {
        super(); // throws at runtime: T is erased
    }
    public T deserialize(byte[] message) { ... }
}

// after
public class MyGenericSchema<T> extends AbstractDeserializationSchema<T> {
    public MyGenericSchema(Class<T> type) {
        super(type); // passes type explicitly
    }
    public T deserialize(byte[] message) { ... }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate before instantiation that the type is concretely bound
Class<?> typeClass = /* resolved at runtime */;
if (typeClass == null) {
    throw new IllegalArgumentException(
        "Cannot construct generic schema without an explicit type.");
}
// Then use the explicit constructor
AbstractDeserializationSchema<MyType> schema = new MySchema(typeClass);

Type guard

// Narrow: if the schema declares a generic T, require the Class/TypeInformation ctor
public static <T> boolean isSafelyConstructible(Class<? extends AbstractDeserializationSchema<T>> clazz) {
    try {
        return java.util.Arrays.stream(clazz.getConstructors())
            .anyMatch(c -> c.getParameterCount() == 1
                && (c.getParameterTypes()[0] == Class.class
                    || c.getParameterTypes()[0] == TypeInformation.class));
    } catch (Exception e) {
        return false;
    }
}

Try / catch

// Not recommended — fix the constructor instead. But if catching:
try {
    schema = new MyGenericSchema<>();
} catch (FlinkRuntimeException e) {
    if (e.getMessage().contains("generic variable")) {
        // re-construct with explicit type
        schema = new MyGenericSchema<>(MyType.class);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: A subclass declares a generic type parameter (e.g. class MySchema<T> extends AbstractDeserializationSchema<T>) and relies on the implicit no-arg constructor instead of calling super(typeClass) or super(typeInfo). The TypeExtractor.createTypeInfo call throws InvalidTypesException, which the constructor wraps in this FlinkRuntimeException.

Common situations: Writing a reusable/generic deserialization schema library that is parameterized over a type T; refactoring a concrete schema to be generic without updating the constructor call; reusing a schema class across different POJO types.

Related errors


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