apache/flink · error · UnsupportedOperationException

Unsupported operation '%s' for row kind.

Error message

Unsupported operation '%s' for row kind.

What it means

Thrown by DebeziumAvroSerializationSchema.serialize() when the RowData's RowKind is not one of the four handled cases (INSERT, UPDATE_AFTER, UPDATE_BEFORE, DELETE). RowKind only defines those four values in stock Flink, so this branch is effectively defensive: it fires when a custom RowKind short-string was injected or a future Flink version adds kinds the serializer has not been taught.

Source

Thrown at flink-formats/flink-avro-confluent-registry/src/main/java/org/apache/flink/formats/avro/registry/confluent/debezium/DebeziumAvroSerializationSchema.java:123

    @Override
    public byte[] serialize(RowData rowData) {
        try {
            switch (rowData.getRowKind()) {
                case INSERT:
                case UPDATE_AFTER:
                    outputReuse.setField(0, null);
                    outputReuse.setField(1, rowData);
                    outputReuse.setField(2, OP_INSERT);
                    return avroSerializer.serialize(outputReuse);
                case UPDATE_BEFORE:
                case DELETE:
                    outputReuse.setField(0, rowData);
                    outputReuse.setField(1, null);
                    outputReuse.setField(2, OP_DELETE);
                    return avroSerializer.serialize(outputReuse);
                default:
                    throw new UnsupportedOperationException(
                            format(
                                    "Unsupported operation '%s' for row kind.",
                                    rowData.getRowKind()));
            }
        } catch (Throwable t) {
            throw new RuntimeException(format("Could not serialize row '%s'.", rowData), t);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        DebeziumAvroSerializationSchema that = (DebeziumAvroSerializationSchema) o;

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Normalize RowKind upstream: map any custom kind to one of +I/-U/+U/-D before the sink (e.g. treat custom upserts as UPDATE_AFTER/INSERT).
  2. Align versions: use the flink-avro-confluent-registry artifact built for your Flink runtime version.
  3. Audit any code calling RowKind.of(...) or constructing GenericRowData with kinds to confirm they only use the standard four.

Example fix

// before
rowData.setRowKind(RowKind.of("X")); // custom kind -> hits default branch

// after
rowData.setRowKind(RowKind.UPDATE_AFTER);
Defensive patterns

Strategy: type-guard

Type guard

private static final Set<String> SUPPORTED_KINDS =
    Set.of("+I", "-U", "+U", "-D");
static boolean isSerializableKind(RowKind k) {
    return SUPPORTED_KINDS.contains(k.shortString());
}

Try / catch

catch (RuntimeException e) { if (e.getCause() instanceof UnsupportedOperationException) { /* normalize row kind upstream and re-emit, or drop row to DLQ */ } else throw e; }

Prevention

When it happens

Trigger: Constructing RowData with RowKind.of(short) custom values in a user function feeding this sink; forwarding rows from a source that invents new kinds; running a mismatched flink-avro-confluent-registry jar (older serializer) against a newer runtime with extended RowKinds.

Common situations: Custom connectors or UDFs labeling rows with bespoke kinds; version skew between shaded format jar and runtime; test fixtures building RowKind by string.

Related errors


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