{"record":{"id":"1fed709ae242dc07","repo":"apache/flink","slug":"could-not-create-a-restore-serializer-for-enum","errorCode":null,"errorMessage":"Could not create a restore serializer for enum {}. Probably because an enum value was removed.","messagePattern":"Could not create a restore serializer for enum (.+?)\\. Probably because an enum value was removed\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/EnumSerializer.java","lineNumber":227,"sourceCode":"                out.writeUTF(enumConstant.name());\n            }\n        }\n\n        @Override\n        public void readSnapshot(int readVersion, DataInputView in, ClassLoader userCodeClassLoader)\n                throws IOException {\n            enumClass = InstantiationUtil.resolveClassByName(in, userCodeClassLoader);\n\n            int numEnumConstants = in.readInt();\n\n            @SuppressWarnings(\"unchecked\")\n            T[] previousEnums = (T[]) Array.newInstance(enumClass, numEnumConstants);\n            for (int i = 0; i < numEnumConstants; i++) {\n                String enumName = in.readUTF();\n                try {\n                    previousEnums[i] = Enum.valueOf(enumClass, enumName);\n                } catch (IllegalArgumentException e) {\n                    throw new IllegalStateException(\n                            \"Could not create a restore serializer for enum \"\n                                    + enumClass\n                                    + \". Probably because an enum value was removed.\");\n                }\n            }\n\n            this.enums = previousEnums;\n        }\n\n        @Override\n        public TypeSerializer<T> restoreSerializer() {\n            checkState(enumClass != null, \"Enum class can not be null.\");\n\n            return new EnumSerializer<>(enumClass, enums);\n        }\n\n        @Override\n        public TypeSerializerSchemaCompatibility<T> resolveSchemaCompatibility(","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/EnumSerializer.java#L209-L245","documentation":"EnumSerializer stores enum constants by name. On restore, EnumSerializerSnapshot.readSnapshot reads each checkpointed enum name and maps it back with Enum.valueOf; if a name no longer exists in the current enum class, it throws IllegalStateException. This guards against silent data corruption because the ordinal/name mapping must resolve every saved value.","triggerScenarios":"Restoring from a savepoint/checkpoint after removing or renaming an enum constant that was present when the state was checkpointed; the EnumSerializerSnapshot.restoreSerializer/readSnapshot path cannot find the old constant.","commonSituations":"Refactoring an enum by deleting a value (e.g., removing a Status.PENDING); renaming enum constants; shrinking an enum used as a keyed state or field type; deploying a new JAR version that dropped an enum member.","solutions":["Add the missing enum constant back (marked @Deprecated) so restore can resolve it, then redeploy.","If removal is intended, run a state migration: restore on the old code, rewrite/transform the state, take a new savepoint, then deploy the new enum.","Never delete enum constants that appear in checkpointed state; prefer deprecation to preserve the name mapping.","If the enum is freshly introduced, discard the incompatible savepoint and start a new job.","Audit enum usages in keyed/operator state before changing them in a release."],"exampleFix":"// before: enum constant PENDING was removed from the deployed jar\n//   public enum Status { ACTIVE, INACTIVE }  // restore fails: 'PENDING' not found\n// after: keep the constant to allow restore\n//   public enum Status { ACTIVE, INACTIVE, @Deprecated PENDING }","handlingStrategy":"try-catch","validationCode":"// Before deploy, verify every previously-checkpointed enum name still exists\nSet<String> oldNames = Set.of(\"ACTIVE\", \"INACTIVE\", \"PENDING\"); // from the old savepoint\nSet<String> currentNames = Arrays.stream(Status.class.getEnumConstants()).map(Enum::name).collect(Collectors.toSet());\nList<String> removed = oldNames.stream().filter(n -> !currentNames.contains(n)).collect(Collectors.toList());\nif (!removed.isEmpty()) {\n    throw new IllegalStateException(\"Enum constants removed since last savepoint (restore will fail): \" + removed);\n}","typeGuard":null,"tryCatchPattern":"try {\n    env.fromSavepoint(savepointPath);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"restore serializer for enum\")) {\n        log.error(\"An enum constant used in state was removed; re-add it (deprecated) or run a state migration\");\n    }\n    throw e;\n}","preventionTips":["Never delete enum constants that participate in checkpointed state; deprecate instead.","Keep a registry of enums used in keyed/operator state and audit changes before release.","Run a savepoint restore test in CI for jobs with enum-typed state.","When refactoring enums, perform a state migration: restore old, rewrite, take new savepoint."],"tags":["serialization","state-restore","enum","schema-evolution"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}