apache/iceberg · error · UnsupportedOperationException
Unknown row kind:
Error message
Unknown row kind:
What it means
BaseDeltaTaskWriter.write dispatches RowData by RowKind: INSERT rows go to the data writer, DELETE rows to the delete writer, and UPDATE_BEFORE/UPDATE_AFTER are routed appropriately (before-images ignored or used). Any other RowKind (e.g. a future kind) reaches the default branch and throws this UnsupportedOperationException.
Source
Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/sink/BaseDeltaTaskWriter.java:109
break;
case UPDATE_BEFORE:
if (upsert) {
break; // UPDATE_BEFORE is not necessary for UPSERT, we do nothing to prevent delete one
// row twice
}
writer.delete(row);
break;
case DELETE:
if (upsert) {
writer.deleteKey(keyProjection.wrap(row));
} else {
writer.delete(row);
}
break;
default:
throw new UnsupportedOperationException("Unknown row kind: " + row.getRowKind());
}
}
protected class RowDataDeltaWriter extends BaseEqualityDeltaWriter {
RowDataDeltaWriter(PartitionKey partition, PartitioningDVWriter<RowData> dvFileWriter) {
super(partition, schema, deleteSchema, DeleteGranularity.FILE, dvFileWriter);
}
@Override
protected StructLike asStructLike(RowData data) {
return wrapper.wrap(data);
}
@Override
protected StructLike asStructLikeKey(RowData data) {
return keyWrapper.wrap(data);
}
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Normalize incoming rows to INSERT/DELETE/UPDATE_BEFORE/UPDATE_BEFORE kinds before writing to the Iceberg sink.
- Align the Flink and Iceberg versions so RowKind enums are consistent.
- Audit upstream transformations (e.g. changelog producers) that might emit unexpected row kinds.
Example fix
// before
emit(row) // row with unknown RowKind
// after
if (row.getRowKind() == RowKind.INSERT || row.getRowKind() == RowKind.DELETE) {
emit(row);
} Defensive patterns
Strategy: validation
Validate before calling
RowKind kind = row.getRowKind();
if (kind != RowKind.INSERT && kind != RowKind.DELETE
&& kind != RowKind.UPDATE_BEFORE && kind != RowKind.UPDATE_AFTER) {
throw new IllegalArgumentException("Row kind not supported by Iceberg sink: " + kind);
} Type guard
boolean writableKind(RowData row) {
RowKind k = row.getRowKind();
return k == RowKind.INSERT || k == RowKind.DELETE
|| k == RowKind.UPDATE_BEFORE || k == RowKind.UPDATE_AFTER;
} Try / catch
try {
writer.write(row);
} catch (UnsupportedOperationException e) {
LOG.error("RowKind {} not supported by BaseDeltaTaskWriter", row.getRowKind(), e);
throw e;
} Prevention
- Normalize changelog streams to standard Flink RowKind values before the Iceberg sink.
- Keep Flink and Iceberg connector versions aligned so RowKind definitions match.
- Unit-test custom operators that synthesize RowData for row-kind correctness.
When it happens
Trigger: Writing a RowData whose getRowKind() is not INSERT, DELETE, UPDATE_BEFORE, or UPDATE_AFTER into an Iceberg Flink sink — practically only possible with custom/updated Flink RowKind values.
Common situations: Custom Flink pipelines that fabricate RowData with unusual row kinds, or running a pipeline built against a newer Flink that introduced a new RowKind into an older Iceberg sink.
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
- Unknown row kind:
- Unknown row kind: <row.getRowKind()>
- WriterSink is used only for writing; committing is handled b
- Altering schema is not supported in the old alterTable API.
- Altering partition keys is not supported yet.
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/758ed9763f362f95.
Report an issue: GitHub.