apache/iceberg · error · java.lang.UnsupportedOperationException
Cannot set row kind in the RowDataProjection
Error message
Cannot set row kind in the RowDataProjection
What it means
RowDataProjection wraps a projected view over another RowData and deliberately forbids mutating the row kind: setRowKind(RowKind) unconditionally throws UnsupportedOperationException. Row kind (INSERT/DELETE/UPDATE_BEFORE/UPDATE_AFTER) belongs to the underlying source row, not a projection of it.
Solutions
- Call setRowKind on the underlying/original RowData (the one wrapped by the projection) instead of the projection itself.
- Copy the projected fields into a new GenericRowData and set the RowKind on that copy.
- Restructure the pipeline to apply row-kind changes before projection.
Example fix
// before projectedRow.setRowKind(RowKind.DELETE); // after GenericRowData out = new GenericRowData(projectedRow.getArity()); for (int i = 0; i < projectedRow.getArity(); i++) out.setField(i, RowData.createFieldGetter(...)); out.setRowKind(RowKind.DELETE);
Defensive patterns
Strategy: try-catch
Validate before calling
// java
if (row instanceof RowDataProjection) {
throw new IllegalStateException("setRowKind is unsupported on RowDataProjection; mutate the source row instead");
} Type guard
// java
RowData mutableRow = (row instanceof RowDataProjection)
? null // projection is immutable; use the original row
: row; Try / catch
// java
try {
row.setRowKind(RowKind.INSERT);
} catch (UnsupportedOperationException e) {
// fall back: copy fields into GenericRowData and set kind on the copy
} Prevention
- Treat RowDataProjection as a read-only view; only read fields and getRowKind from it.
- Set RowKind on the upstream source RowData before projection, or build a fresh GenericRowData for output.
- Avoid generic code that blindly mutates any RowData instance.
When it happens
Trigger: Calling setRowKind(...) on a RowDataProjection instance — e.g. generic Flink code that assumes every RowData is mutable (as with GenericRowData) and tries to change the changelog kind on a projected row.
Common situations: Flink pipeline code applying row-kind updates (dedup, CDC processing) to rows after they passed through a projection; frameworks that mutate RowData in place hitting the wrapper instead of the original row.
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
- Cannot set row kind in the RowDataProjection
- Cannot set row kind in the RowDataProjection
- Cannot set row kind in the RowDataProjection
- Could not set a field in the RowDataWrapper because rowData…
- Could not set a field in the RowDataWrapper because rowData…
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/e853ebf1b66bc3d9.
Report an issue: GitHub.
Appendix: source
Thrown at flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/data/RowDataProjection.java:198
private Object getValue(int pos) {
Preconditions.checkState(rowData != null, "Row data not wrapped");
return getters[pos].getFieldOrNull(rowData);
}
@Override
public int getArity() {
return getters.length;
}
@Override
public RowKind getRowKind() {
Preconditions.checkState(rowData != null, "Row data not wrapped");
return rowData.getRowKind();
}
@Override
public void setRowKind(RowKind kind) {
throw new UnsupportedOperationException("Cannot set row kind in the RowDataProjection");
}
@Override
public boolean isNullAt(int pos) {
return getValue(pos) == null;
}
@Override
public boolean getBoolean(int pos) {
return (boolean) getValue(pos);
}
@Override
public byte getByte(int pos) {
return (byte) getValue(pos);
}
@OverrideView on GitHub (pinned to 86d9c8fc54)