apache/seatunnel · error · IllegalArgumentException

Unrecognized row kind:<rowKind>

Error message

Unrecognized row kind:<rowKind>

What it means

SeaTunnelRowSerializer.parseDeleteSign maps RowKind to the Doris stream-load delete sign (0 for insert/update-after, 1 for delete/update-before). RowKind.READ or any unexpected kind throws IllegalArgumentException because the serializer cannot decide whether the row is an insert or a delete.

Source

Thrown at seatunnel-connectors-v2/connector-doris/src/main/java/org/apache/seatunnel/connectors/doris/serialize/SeaTunnelRowSerializer.java:123

    }

    public byte[] buildJsonString(SeaTunnelRow row) {

        return serialize.serialize(row);
    }

    public byte[] buildCSVString(SeaTunnelRow row) {

        return serialize.serialize(row);
    }

    public String parseDeleteSign(RowKind rowKind) {
        if (RowKind.INSERT.equals(rowKind) || RowKind.UPDATE_AFTER.equals(rowKind)) {
            return "0";
        } else if (RowKind.DELETE.equals(rowKind) || RowKind.UPDATE_BEFORE.equals(rowKind)) {
            return "1";
        } else {
            throw new IllegalArgumentException("Unrecognized row kind:" + rowKind.toString());
        }
    }

    @Override
    public void open() throws IOException {}

    @Override
    public byte[] serialize(SeaTunnelRow seaTunnelRow) throws IOException {

        if (enableDelete) {

            List<Object> newFields = new ArrayList<>(Arrays.asList(seaTunnelRow.getFields()));
            newFields.add(parseDeleteSign(seaTunnelRow.getRowKind()));
            seaTunnelRow = new SeaTunnelRow(newFields.toArray());
        }

        if (JSON.equals(type)) {
            return buildJsonString(seaTunnelRow);

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Ensure the source emits CDC semantics (CDC-enabled source or SeaTunnelRow with correct RowKind), or disable delete-sign handling for non-CDC pipelines
  2. Normalize RowKind in a transform: map READ rows to INSERT before the sink
  3. Check that upstream transforms don't overwrite the RowKind

Example fix

// before
SeaTunnelRow row = new SeaTunnelRow(values); // RowKind.READ
// after
row.setRowKind(RowKind.INSERT);
Defensive patterns

Strategy: type-guard

Validate before calling

RowKind k = row.getRowKind();
if (!(k == RowKind.INSERT || k == RowKind.UPDATE_AFTER || k == RowKind.DELETE || k == RowKind.UPDATE_BEFORE)) throw new IllegalStateException("non-CDC row in CDC sink: " + k);

Type guard

boolean isCdcRowKind(RowKind k) { return k == RowKind.INSERT || k == RowKind.UPDATE_AFTER || k == RowKind.DELETE || k == RowKind.UPDATE_BEFORE; }

Prevention

When it happens

Trigger: Sink receiving rows whose RowKind is not INSERT/UPDATE_AFTER/DELETE/UPDATE_BEFORE — typically RowKind.READ produced by a non-CDC source when `cdc-enabled`/deletable semantics were wrongly assumed, or custom transforms resetting the row kind.

Common situations: Feeding a batch/snapshot source into a Doris sink configured for CDC (enable-delete with primary-key table); a transform that constructs SeaTunnelRow with RowKind.READ; version changes in RowKind enum handling.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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