apache/flink · error · UnsupportedOperationException

Unsupported operation '%s' for row kind.

Error message

Unsupported operation '%s' for row kind.

What it means

Thrown by DebeziumJsonSerializationSchema.serialize when the incoming RowData has a RowKind not in {INSERT, UPDATE_AFTER, UPDATE_BEFORE, DELETE}. The serializer maps INSERT/UPDATE_AFTER to the 'r'/'c' ops and UPDATE_BEFORE/DELETE to the 'd' op; any other RowKind hits the default branch with UnsupportedOperationException, which is then wrapped into RuntimeException('Could not serialize row ...').

Source

Thrown at flink-formats/flink-json/src/main/java/org/apache/flink/formats/json/debezium/DebeziumJsonSerializationSchema.java:94

    @Override
    public byte[] serialize(RowData rowData) {
        try {
            switch (rowData.getRowKind()) {
                case INSERT:
                case UPDATE_AFTER:
                    genericRowData.setField(0, null);
                    genericRowData.setField(1, rowData);
                    genericRowData.setField(2, OP_INSERT);
                    return jsonSerializer.serialize(genericRowData);
                case UPDATE_BEFORE:
                case DELETE:
                    genericRowData.setField(0, rowData);
                    genericRowData.setField(1, null);
                    genericRowData.setField(2, OP_DELETE);
                    return jsonSerializer.serialize(genericRowData);
                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;
        }
        DebeziumJsonSerializationSchema that = (DebeziumJsonSerializationSchema) o;

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Ensure upstream operators only emit RowKind.INSERT, UPDATE_BEFORE, UPDATE_AFTER, or DELETE into a debezium-json sink.
  2. Normalize RowKinds in a preceding map: convert non-CDC kinds (e.g. clamp everything else to INSERT) before the sink.
  3. If the exception surfaces as 'Could not serialize row', inspect the cause — this UnsupportedOperationException indicates the row kind, not the payload, is the problem.

Example fix

// before
genericRow.setRowKind(RowKind.fromShortValue((short) 7)); // unknown kind
out.collect(genericRow);
// after
genericRow.setRowKind(RowKind.INSERT);
out.collect(genericRow);
Defensive patterns

Strategy: type-guard

Type guard

private static final Set<RowKind> CDC_KINDS = EnumSet.of(
        RowKind.INSERT, RowKind.UPDATE_BEFORE, RowKind.UPDATE_AFTER, RowKind.DELETE);

static boolean isCdcRowKind(RowData row) {
    return CDC_KINDS.contains(row.getRowKind());
}

Try / catch

Catch RuntimeException around serialization, inspect getCause() instanceof UnsupportedOperationException and its message for 'row kind' before deciding to skip or fail.

Prevention

When it happens

Trigger: Serializing a RowData whose RowKind is a custom/extended kind beyond the four CDC kinds — practically only reachable via a custom pipeline that sets RowKind via valueOf on an unknown short value, or a downstream operator emitting a non-standard kind into a debezium-json sink.

Common situations: Custom sources or ProcessFunctions reusing RowKind short codes outside 0..3; version changes introducing new RowKind enum values; test harnesses constructing GenericRowData with arbitrary RowKind.

Related errors


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