apache/flink · error · IllegalArgumentException

A flattened field can not be a composite type

Error message

A flattened field can not be a composite type

What it means

Thrown by the FlatFieldDescriptor constructor when the supplied TypeInformation is itself a CompositeType (i.e. Tuple, POJO, Row). A FlatFieldDescriptor represents a fully flattened leaf field, which by definition must be an atomic (non-composite) type. Constructing one with a composite type signals a bug in field-expression resolution.

Source

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

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

    @PublicEvolving
    protected interface TypeComparatorBuilder<T> {
        void initializeTypeComparatorBuilder(int size);

        void addComparatorField(int fieldId, TypeComparator<?> comparator);

        TypeComparator<T> createTypeComparator(ExecutionConfig config);
    }

    @PublicEvolving
    public static class FlatFieldDescriptor {
        private int keyPosition;
        private TypeInformation<?> type;

        public FlatFieldDescriptor(int keyPosition, TypeInformation<?> type) {
            if (type instanceof CompositeType) {
                throw new IllegalArgumentException("A flattened field can not be a composite type");
            }
            this.keyPosition = keyPosition;
            this.type = type;
        }

        public int getPosition() {
            return keyPosition;
        }

        public TypeInformation<?> getType() {
            return type;
        }

        @Override
        public String toString() {
            return "FlatFieldDescriptor [position=" + keyPosition + " typeInfo=" + type + "]";
        }
    }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. If implementing a custom CompositeType, ensure getFlatFields recurses into nested composite types until only atomic FlatFieldDescriptors remain.
  2. If you are a user hitting this via keyBy or field selectors, check that your field expression targets a leaf field, not a nested composite object.
  3. Avoid selecting a whole nested object as a key; instead select a specific field within it (e.g. 'nested.id' not 'nested').

Example fix

// before — selecting a nested composite object as a flat key
// class Outer { Nested nested; }  class Nested { int id; }
ds.keyBy("nested") // resolves to composite Nested -> FlatFieldDescriptor rejects

// after — select the leaf atomic field
ds.keyBy("nested.id") // ok
Defensive patterns

Strategy: validation

Validate before calling

// If building FlatFieldDescriptor manually, guard against composite types
TypeInformation<?> fieldType = compositeType.getTypeAt(pos);
if (fieldType instanceof CompositeType) {
    throw new IllegalStateException(
        "Field at " + pos + " is composite; drill into a leaf field instead.");
}
FlatFieldDescriptor desc = new FlatFieldDescriptor(pos, fieldType);

Prevention

When it happens

Trigger: Internal code or a custom CompositeType subclass calling new FlatFieldDescriptor(pos, compositeTypeInfo). Also triggered when a field expression with a trailing dot or wildcard resolves to a composite type instead of drilling down to an atomic field. This is primarily an internal invariant, not a user-facing API in most cases.

Common situations: Implementing a custom CompositeType with a buggy getFlatFields override that stops at a composite field. A field expression like "nested." (trailing dot) or an empty selector on a nested tuple that does not recurse. Flink version mismatch where a custom type's field resolution logic changed.

Related errors


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