{"record":{"id":"fc693b183ffc0a31","repo":"apache/flink","slug":"the-class-is-not-a-subclass-of","errorCode":null,"errorMessage":"The class {} is not a subclass of {}","messagePattern":"The class (.+?) is not a subclass of (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"critical","filePath":"flink-core/src/main/java/org/apache/flink/util/InstantiationUtil.java","lineNumber":673,"sourceCode":"\n        final String className = in.readUTF();\n        final Class<?> rawClazz;\n        try {\n            rawClazz = Class.forName(className, false, cl);\n        } catch (ClassNotFoundException e) {\n            String error = \"Could not find class '\" + className + \"' in classpath.\";\n            if (className.contains(\"SerializerConfig\")) {\n                error +=\n                        \" TypeSerializerConfigSnapshot and it's subclasses are not supported since Flink 1.17.\"\n                                + \" If you are using built-in serializers, please first migrate to Flink 1.16.\"\n                                + \" If you are using custom serializers, please migrate them to\"\n                                + \" TypeSerializerSnapshot using Flink 1.16.\";\n            }\n            throw new IOException(error, e);\n        }\n\n        if (!supertype.isAssignableFrom(rawClazz)) {\n            throw new IOException(\n                    \"The class \" + className + \" is not a subclass of \" + supertype.getName());\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        Class<T> clazz = (Class<T>) rawClazz;\n        return clazz;\n    }\n\n    // --------------------------------------------------------------------------------------------\n\n    /** Private constructor to prevent instantiation. */\n    private InstantiationUtil() {\n        throw new RuntimeException();\n    }\n}\n","sourceCodeStart":655,"sourceCodeEnd":689,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/util/InstantiationUtil.java#L655-L689","documentation":"After successfully loading the class named in a checkpoint's metadata via Class.forName, InstantiationUtil.resolveClassByName verifies it is a subtype of the expected supertype (e.g. TypeSerializerSnapshot). If supertype.isAssignableFrom(rawClazz) is false, this IOException is thrown, meaning the stored class exists but does not implement/extend what the restore code requires.","triggerScenarios":"Restoring a checkpoint/savepoint where the serializer snapshot class name resolves to an existing class, but that class does not implement the required interface — typically an old TypeSerializerConfigSnapshot subclass being checked against TypeSerializerSnapshot, or a refactored class that changed its type hierarchy.","commonSituations":"Flink upgrade from 1.x to 1.17+ where the old snapshot class is still on the classpath but implements the removed API; a user refactored a custom serializer snapshot so it no longer implements TypeSerializerSnapshot; two versions of a class in different jars and the wrong one wins classloading.","solutions":["Read the two class names in the message: the stored class and the expected supertype, then check why the subtype relation is broken (usually the removed TypeSerializerConfigSnapshot API).","If upgrading across 1.17: perform an intermediate restore on Flink 1.16 with serializers already migrated to TypeSerializerSnapshot, then take a new savepoint.","Fix the custom class so it implements the expected interface (e.g. TypeSerializerSnapshot) and rebuild the user jar.","Check for duplicate/legacy jars on the classpath that shadow the correct snapshot class."],"exampleFix":"// before\npublic class MySnapshot extends SimpleTypeSerializerSnapshot<MyType> {} // but class in jar v1 implements TypeSerializerConfigSnapshot\n\n// after: ensure the snapshot class on the runtime classpath implements the required supertype\npublic class MySnapshot extends SimpleTypeSerializerSnapshot<MyType> {\n    public MySnapshot() { super(MySerializer::new); }\n}","handlingStrategy":"validation","validationCode":"Class<?> stored = Class.forName(snapshotClassName, false, cl);\nif (!TypeSerializerSnapshot.class.isAssignableFrom(stored)) {\n    throw new IllegalStateException(snapshotClassName + \" does not implement TypeSerializerSnapshot; checkpoint format predates Flink 1.17 - migrate via 1.16\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Version checkpoints explicitly and refuse restore across incompatible major versions","Run restore in a staging job first when upgrading Flink","Avoid keeping legacy serializer jars that shadow new implementations"],"tags":["checkpointing","restore","upgrade","type-hierarchy","serialization"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}