apache/flink · critical · IOException

Could not find class '{}' in classpath. TypeSerializerConfig

Error message

Could not find class '{}' in classpath. TypeSerializerConfigSnapshot and it's subclasses are not supported since Flink 1.17. If you are using built-in serializers, please first migrate to Flink 1.16. If you are using custom serializers, please migrate them to TypeSerializerSnapshot using Flink 1.16.

What it means

InstantiationUtil.resolveClassByName (used when restoring serializer snapshots from checkpoints/savepoints) could not load the class named in the checkpoint metadata via Class.forName. When the missing class name contains 'SerializerConfig', the message is extended: TypeSerializerConfigSnapshot and its subclasses were removed in Flink 1.17, so checkpoints written with the old snapshot format by pre-1.16 jobs cannot be restored on 1.17+.

Source

Thrown at flink-core/src/main/java/org/apache/flink/util/InstantiationUtil.java:669

     *     found, or the class is not a subtype of the given supertype class.
     */
    public static <T> Class<T> resolveClassByName(
            DataInputView in, ClassLoader cl, Class<? super T> supertype) throws IOException {

        final String className = in.readUTF();
        final Class<?> rawClazz;
        try {
            rawClazz = Class.forName(className, false, cl);
        } catch (ClassNotFoundException e) {
            String error = "Could not find class '" + className + "' in classpath.";
            if (className.contains("SerializerConfig")) {
                error +=
                        " TypeSerializerConfigSnapshot and it's subclasses are not supported since Flink 1.17."
                                + " If you are using built-in serializers, please first migrate to Flink 1.16."
                                + " If you are using custom serializers, please migrate them to"
                                + " TypeSerializerSnapshot using Flink 1.16.";
            }
            throw new IOException(error, e);
        }

        if (!supertype.isAssignableFrom(rawClazz)) {
            throw new IOException(
                    "The class " + className + " is not a subclass of " + supertype.getName());
        }

        @SuppressWarnings("unchecked")
        Class<T> clazz = (Class<T>) rawClazz;
        return clazz;
    }

    // --------------------------------------------------------------------------------------------

    /** Private constructor to prevent instantiation. */
    private InstantiationUtil() {
        throw new RuntimeException();
    }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. If you jumped to Flink 1.17+ from a version <=1.16: restore the old checkpoint first on Flink 1.16 to let it migrate snapshots to TypeSerializerSnapshot, take a new checkpoint, then upgrade.
  2. For custom serializers: port the serializer to implement TypeSerializerSnapshot (replacing TypeSerializerConfigSnapshot) while still on Flink 1.16, run a savepoint, then upgrade.
  3. Ensure the jar containing the missing class is on the classpath of the job being restored (attach it via -C / pipeline.classpaths or bundle it in the user jar).
  4. Verify the class name in the error against your project for renames/refactors and keep class names of snapshot classes stable across versions.

Example fix

// before (custom serializer, pre-1.16 style)
public class MySerializerSnapshot<T> extends TypeSerializerConfigSnapshot<T> { ... }

// after
public class MySerializerSnapshot<T> implements TypeSerializerSnapshot<T> {
    @Override public int getCurrentVersion() { return 1; }
    // readSnapshot/writeSnapshot/resolveSchemaCompatibility implemented
}
Defensive patterns

Strategy: validation

Validate before calling

// Before restore, confirm every snapshot class resolves on this classpath
String cn = readSnapshotClassNameFromCheckpoint();
try {
    Class.forName(cn, false, Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
    throw new IllegalStateException("Checkpoint references missing class " + cn + " - attach its jar or migrate via Flink 1.16", e);
}

Try / catch

try {
    jobEnv.execute();
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().contains("Could not find class")) {
        // surface migration guidance instead of raw stack trace
    }
}

Prevention

When it happens

Trigger: Restoring a checkpoint/savepoint whose state serializer snapshot references a class that is not on the classpath (Class.forName throws ClassNotFoundException). The long migration hint appears when className contains 'SerializerConfig', i.e. a pre-1.17 TypeSerializerConfigSnapshot class is referenced.

Common situations: Upgrading a job straight from Flink <=1.16 to 1.17+ and restoring an old checkpoint that stores TypeSerializerConfigSnapshot metadata; a user jar containing a custom serializer snapshot class was not attached on restore; class was renamed or shaded between application versions.

Related errors


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