apache/seatunnel · error · KuduConnectorException

UNSUPPORTED_OPERATION

UNSUPPORTED_OPERATION

Error message

Unsupported write row kind: 

What it means

KuduRowSerializer.serializeRow() maps a SeaTunnelRow's RowKind to a Kudu write operation (INSERT/UPSERT/DELETE). RowKinds outside the supported set fall into the default branch and throw KuduConnectorException with UNSUPPORTED_OPERATION, naming the offending RowKind.

Source

Thrown at seatunnel-connectors-v2/connector-kudu/src/main/java/org/apache/seatunnel/connectors/seatunnel/kudu/serialize/KuduRowSerializer.java:68

    @Override
    public Operation serializeRow(SeaTunnelRow row) {
        Operation operation;
        switch (row.getRowKind()) {
            case INSERT:
                if (saveMode == KuduSinkConfig.SaveMode.OVERWRITE) {
                    operation = kuduTable.newUpsert();
                    break;
                }
                operation = kuduTable.newInsert();
                break;
            case UPDATE_AFTER:
                operation = kuduTable.newUpsert();
                break;
            case DELETE:
                operation = kuduTable.newDelete();
                break;
            default:
                throw new KuduConnectorException(
                        CommonErrorCodeDeprecated.UNSUPPORTED_OPERATION,
                        "Unsupported write row kind: " + row.getRowKind());
        }
        transform(operation, row);
        return operation;
    }

    private void transform(Operation operation, SeaTunnelRow element) {
        PartialRow row = operation.getRow();
        for (int columnIndex = 0; columnIndex < seaTunnelRowType.getTotalFields(); columnIndex++) {
            SeaTunnelDataType<?> type = seaTunnelRowType.getFieldType(columnIndex);
            try {
                switch (type.getSqlType()) {
                    case BOOLEAN:
                    case TINYINT:
                    case SMALLINT:
                    case INT:
                    case BIGINT:

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Preprocess the stream so only INSERT/UPDATE_AFTER/DELETE rows reach the sink (e.g. use a deduplicate transform)
  2. Configure the sink to upsert (UPDATE_AFTER maps to UPSERT)
  3. Filter out unsupported RowKinds before the sink

Example fix

// before
// UPDATE_BEFORE rows sent to kudu sink
// after
// add transform/dropRowKind or route UPDATE_AFTER -> UPSERT before sink
Defensive patterns

Strategy: validation

Validate before calling

// Filter unsupported RowKinds before the sink
if (row.getRowKind() == RowKind.INSERT || row.getRowKind() == RowKind.UPDATE_AFTER || row.getRowKind() == RowKind.DELETE) { /* send to sink */ } else { /* drop or route */ }

Try / catch

try { serializer.serializeRow(row); } catch (KuduConnectorException e) {
  if ("UNSUPPORTED_OPERATION".equals(e.getSeaTunnelErrorCode())) { /* drop/transform row */ }
}

Prevention

When it happens

Trigger: Writing a row whose RowKind is UPDATE_BEFORE, UPDATE_AFTER, or any kind not mapped to a Kudu operation when using the Kudu sink.

Common situations: CDC pipelines (e.g. MySQL CDC) emitting UPDATE_BEFORE/UPDATE_AFTER rows directly into a Kudu sink without aggregation or without configuring sink support for update semantics.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/ca9f7e0e0f580874. Report an issue: GitHub.