apache/flink · error · IllegalStateException

Undefined compatibility type.

Error message

Undefined compatibility type.

What it means

Thrown by CompositeTypeSerializerUtil.constructIntermediateCompatibilityResult when a nested serializer's resolveCompatibility call returns a TypeSerializerSchemaCompatibility that matches none of the four recognized outcomes (incompatible, compatibleAfterMigration, compatibleWithReconfiguredSerializer, compatibleAsIs). This is an internal invariant violation indicating a custom TypeSerializerSnapshot returned an invalid or null compatibility result.

Solutions

  1. Audit any custom TypeSerializerSnapshot.resolveSchemaCompatibility implementation to ensure it returns only values from the four standard factory methods.
  2. If using a third-party serializer library, upgrade it or check its Flink integration for a known bug.
  3. Replace the custom snapshot with one that delegates to SimpleTypeSerializerSnapshot or CompositeTypeSerializerSnapshot to avoid hand-rolling compatibility logic.
  4. Add a unit test that calls resolveSchemaCompatibility with old and new snapshots and asserts the returned Type.
Defensive patterns

Strategy: try-catch

Validate before calling

// Unit-test your custom snapshot to ensure it returns a standard compatibility result
TypeSerializerSchemaCompatibility<?> c =
    newSnapshot.resolveSchemaCompatibility(oldSnapshot);
if (!c.isCompatibleAsIs() && !c.isCompatibleAfterMigration()
        && !c.isCompatibleWithReconfiguredSerializer() && !c.isIncompatible()) {
    throw new AssertionError("Custom snapshot returned an invalid compatibility result");
}

Try / catch

try {
    backend.restore(state);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Undefined compatibility type")) {
        // a custom TypeSerializerSnapshot returned an invalid result
        log.error("A custom serializer snapshot returned an unsupported compatibility result", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: A custom TypeSerializerSnapshot implementation whose resolveSchemaCompatibility method returns null or a TypeSerializerSchemaCompatibility built through an unsupported/undocumented code path. This should not happen with the standard factory methods (compatibleAsIs, compatibleAfterMigration, incompatible, compatibleWithReconfiguredSerializer).

Common situations: Implementing a custom serializer and its snapshot incorrectly — returning a raw or improperly-constructed TypeSerializerSchemaCompatibility. A library/framework wrapping Flink serializers with a snapshot that returns an unexpected enum variant. Regression after upgrading a custom serializer library.

Related errors


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

Appendix: source

Thrown at flink-core/src/main/java/org/apache/flink/api/common/typeutils/CompositeTypeSerializerUtil.java:121

            TypeSerializerSchemaCompatibility<?> compatibility =
                    resolveCompatibility(
                            newNestedSerializerSnapshots[i], oldNestedSerializerSnapshots[i]);

            // if any one of the new nested serializers is incompatible, we can just short circuit
            // the result
            if (compatibility.isIncompatible()) {
                return IntermediateCompatibilityResult.definedIncompatibleResult();
            }

            if (compatibility.isCompatibleAfterMigration()) {
                nestedSerializerRequiresMigration = true;
            } else if (compatibility.isCompatibleWithReconfiguredSerializer()) {
                hasReconfiguredNestedSerializers = true;
                nestedSerializers[i] = compatibility.getReconfiguredSerializer();
            } else if (compatibility.isCompatibleAsIs()) {
                nestedSerializers[i] = newNestedSerializerSnapshots[i].restoreSerializer();
            } else {
                throw new IllegalStateException("Undefined compatibility type.");
            }
        }

        if (nestedSerializerRequiresMigration) {
            return IntermediateCompatibilityResult.definedCompatibleAfterMigrationResult();
        }

        if (hasReconfiguredNestedSerializers) {
            return IntermediateCompatibilityResult.undefinedReconfigureResult(nestedSerializers);
        }

        // ends up here if everything is compatible as is
        return IntermediateCompatibilityResult.definedCompatibleAsIsResult(nestedSerializers);
    }

    public static class IntermediateCompatibilityResult<T> {

        private final TypeSerializerSchemaCompatibility.Type compatibilityType;

View on GitHub (pinned to 2f3c205e92)