apache/flink · error · RuntimeException

Row arity of reuse ({}) or from ({}) is incompatible with th

Error message

Row arity of reuse ({}) or from ({}) is incompatible with this serializer's field length ({}).

What it means

RowSerializer.copyPositionBased(Row from, Row reuse) is the reuse-optimized copy path for position-based Rows. It checks that BOTH the source Row ('from') and the reuse Row have arity equal to the serializer's field count. If either mismatches, this RuntimeException names both arities and the expected length. Using a reuse Row with the wrong arity is as invalid as a wrong-arity source.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/RowSerializer.java:212

        if (fieldNames == null) {
            // reuse uses name-based field mode, do a non-reuse copy
            if (reuse.getFieldNames(false) != null) {
                return copy(from);
            }
            return copyPositionBased(from, reuse);
        } else {
            // reuse uses position-based field mode, do a non-reuse copy
            if (reuse.getFieldNames(false) == null) {
                return copy(from);
            }
            return copyNameBased(from, fieldNames, reuse);
        }
    }

    private Row copyPositionBased(Row from, Row reuse) {
        final int length = fieldSerializers.length;
        if (from.getArity() != length || reuse.getArity() != length) {
            throw new RuntimeException(
                    "Row arity of reuse ("
                            + reuse.getArity()
                            + ") or from ("
                            + from.getArity()
                            + ") is "
                            + "incompatible with this serializer's field length ("
                            + length
                            + ").");
        }
        reuse.setKind(from.getKind());
        for (int i = 0; i < length; i++) {
            final Object fromField = from.getField(i);
            if (fromField != null) {
                final Object reuseField = reuse.getField(i);
                if (reuseField != null) {
                    final Object copy = fieldSerializers[i].copy(fromField, reuseField);
                    reuse.setField(i, copy);
                } else {

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Allocate the reuse Row with exactly fieldSerializers.length fields.
  2. Ensure both source and reuse Rows have the same arity as the serializer.
  3. Do not pool or reuse Row objects across serializers with different arities.
  4. After a schema change, discard old reuse Row buffers and reallocate.

Example fix

// before — reuse Row arity does not match serializer
RowSerializer ser = new RowSerializer(new TypeSerializer[]{intSer, strSer}); // length 2
Row reuse = new Row(3); // wrong arity
ser.copy(Row.of(1, "a"), reuse); // reuse arity 3 ≠ 2 → exception

// after — reuse Row matches serializer arity
Row reuse = new Row(2); // matches fieldSerializers.length
ser.copy(Row.of(1, "a"), reuse); // OK
Defensive patterns

Strategy: validation

Validate before calling

// Validate both source and reuse arity before reuse-copy
public static Row safeCopy(RowSerializer ser, Row from, Row reuse) {
    int expected = ser.getArity();
    if (from.getArity() != expected || reuse.getArity() != expected) {
        throw new IllegalArgumentException(
            "Arity mismatch: from=" + from.getArity()
            + ", reuse=" + reuse.getArity() + ", expected=" + expected);
    }
    return ser.copy(from, reuse);
}

Try / catch

try {
    Row result = serializer.copy(from, reuse);
} catch (RuntimeException e) {
    if (e.getMessage().contains("incompatible with this serializer's field length")) {
        log.error("Reuse or source arity wrong: from={}, reuse={}, expected={}",
            from.getArity(), reuse.getArity(), serializer.getArity());
        reuse = serializer.createInstance(); // fix reuse
    }
    throw e;
}

Prevention

When it happens

Trigger: RowSerializer.copy(Row from, Row reuse) is called with either 'from' or 'reuse' having an arity different from fieldSerializers.length. This happens in the reuse-deserialize or reuse-copy code paths that operators use for performance.

Common situations: The reuse Row was created with a different arity than the serializer expects (e.g., pre-allocated for a previous schema version); the source Row has evolved to a different arity while the reuse Row was sized for the old one; a generic reuse pool provides Rows of the wrong size; state restore where the reuse buffer was allocated for a different schema.

Related errors


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