apache/flink · error · InvalidTypesException

Tuple arity '{}' expected but was '{}'.

Error message

Tuple arity '{}' expected but was '{}'.

What it means

Thrown during input type validation for Tuple types when the number of fields in the TupleTypeInfo does not match the number of actual type arguments in the reflected ParameterizedType. For example, the stream carries TupleTypeInfo for Tuple2 (arity 2) but the function's signature declares Tuple3 (arity 3), or vice versa.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/TypeExtractor.java:1564

                    typeHierarchy.add(type);
                    type = typeToClass(type).getGenericSuperclass();
                }

                if (type == Tuple0.class) {
                    return;
                }

                // check if immediate child of Tuple has generics
                if (type instanceof Class<?>) {
                    throw new InvalidTypesException("Parameterized Tuple type expected.");
                }

                TupleTypeInfo<?> tti = (TupleTypeInfo<?>) typeInfo;

                Type[] subTypes = ((ParameterizedType) type).getActualTypeArguments();

                if (subTypes.length != tti.getArity()) {
                    throw new InvalidTypesException(
                            "Tuple arity '"
                                    + tti.getArity()
                                    + "' expected but was '"
                                    + subTypes.length
                                    + "'.");
                }

                for (int i = 0; i < subTypes.length; i++) {
                    validateInfo(new ArrayList<>(typeHierarchy), subTypes[i], tti.getTypeAt(i));
                }
            }
            // check for primitive array
            else if (typeInfo instanceof PrimitiveArrayTypeInfo) {
                Type component;
                // check if array at all
                if (!(type instanceof Class<?>
                                && ((Class<?>) type).isArray()
                                && (component = ((Class<?>) type).getComponentType()) != null)

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Match the Tuple arity in the function signature to the stream's TupleTypeInfo
  2. If you need a different number of fields, add a map to project/reshape the Tuple
  3. Use a POJO with named fields if the schema changes frequently

Example fix

// before — arity mismatch
DataStream<Tuple2<String, Integer>> stream = ...;
stream.map(new MapFunction<Tuple3<String, Integer, Long>, X>() { ... });

// after — match arity
stream.map(new MapFunction<Tuple2<String, Integer>, X>() {
    public X map(Tuple2<String, Integer> value) { ... }
});
Defensive patterns

Strategy: validation

Validate before calling

// Verify Tuple arity matches between stream and function
if (stream.getType() instanceof TupleTypeInfo) {
    int streamArity = ((TupleTypeInfo<?>) stream.getType()).getArity();
    int funcArity = getTupleArityFromFunction(myFunction); // custom helper
    if (streamArity != funcArity) {
        throw new IllegalStateException(
            "Tuple arity mismatch: stream has " + streamArity
            + " fields but function expects " + funcArity);
    }
}

Prevention

When it happens

Trigger: The DataStream's TypeInformation is TupleTypeInfo with a specific arity (e.g. Tuple2, arity 2) but the function's declared input Tuple subclass has a different arity (e.g. Tuple3). The check `subTypes.length != tti.getArity()` fails.

Common situations: Changing the number of fields in a Tuple key or projection without updating the consuming function. Connecting a Tuple2 stream to a function expecting Tuple3. Adding or removing a field in a transformation pipeline without propagating the change.

Related errors


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