apache/flink · critical · IllegalStateException

Could not create a restore serializer for enum {}. Probably

Error message

Could not create a restore serializer for enum {}. Probably because an enum value was removed.

What it means

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.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/typeutils/base/EnumSerializer.java:227

                out.writeUTF(enumConstant.name());
            }
        }

        @Override
        public void readSnapshot(int readVersion, DataInputView in, ClassLoader userCodeClassLoader)
                throws IOException {
            enumClass = InstantiationUtil.resolveClassByName(in, userCodeClassLoader);

            int numEnumConstants = in.readInt();

            @SuppressWarnings("unchecked")
            T[] previousEnums = (T[]) Array.newInstance(enumClass, numEnumConstants);
            for (int i = 0; i < numEnumConstants; i++) {
                String enumName = in.readUTF();
                try {
                    previousEnums[i] = Enum.valueOf(enumClass, enumName);
                } catch (IllegalArgumentException e) {
                    throw new IllegalStateException(
                            "Could not create a restore serializer for enum "
                                    + enumClass
                                    + ". Probably because an enum value was removed.");
                }
            }

            this.enums = previousEnums;
        }

        @Override
        public TypeSerializer<T> restoreSerializer() {
            checkState(enumClass != null, "Enum class can not be null.");

            return new EnumSerializer<>(enumClass, enums);
        }

        @Override
        public TypeSerializerSchemaCompatibility<T> resolveSchemaCompatibility(

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Add the missing enum constant back (marked @Deprecated) so restore can resolve it, then redeploy.
  2. 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.
  3. Never delete enum constants that appear in checkpointed state; prefer deprecation to preserve the name mapping.
  4. If the enum is freshly introduced, discard the incompatible savepoint and start a new job.
  5. Audit enum usages in keyed/operator state before changing them in a release.

Example fix

// before: enum constant PENDING was removed from the deployed jar
//   public enum Status { ACTIVE, INACTIVE }  // restore fails: 'PENDING' not found
// after: keep the constant to allow restore
//   public enum Status { ACTIVE, INACTIVE, @Deprecated PENDING }
Defensive patterns

Strategy: try-catch

Validate before calling

// Before deploy, verify every previously-checkpointed enum name still exists
Set<String> oldNames = Set.of("ACTIVE", "INACTIVE", "PENDING"); // from the old savepoint
Set<String> currentNames = Arrays.stream(Status.class.getEnumConstants()).map(Enum::name).collect(Collectors.toSet());
List<String> removed = oldNames.stream().filter(n -> !currentNames.contains(n)).collect(Collectors.toList());
if (!removed.isEmpty()) {
    throw new IllegalStateException("Enum constants removed since last savepoint (restore will fail): " + removed);
}

Try / catch

try {
    env.fromSavepoint(savepointPath);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("restore serializer for enum")) {
        log.error("An enum constant used in state was removed; re-add it (deprecated) or run a state migration");
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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