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
- 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).
- Align versions: use the flink-avro-confluent-registry artifact built for your Flink runtime version.
- 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
- Only use the four standard RowKind constants
- Map custom upsert semantics to UPDATE_AFTER/UPDATE_BEFORE at the source
- Pin the format jar version to the runtime version
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
- Unknown "op" value "%s". The Debezium Avro message is '%s'
- Can't deserialize Debezium Avro message.
- Could not serialize row '%s'.
- Could not instantiate org.apache.flink.formats.avro.utils.Av
- Failed to serialize row.
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/f40a73444494d0c3.
Report an issue: GitHub.