apache/iceberg · error · java.lang.UnsupportedOperationException

Could not set a field in the RowDataWrapper because rowData

Error message

Could not set a field in the RowDataWrapper because rowData is read-only

What it means

RowDataWrapper adapts a Flink RowData to Iceberg's StructLike interface for reads. Since the underlying RowData is read-only, the set() method has no valid implementation and unconditionally throws UnsupportedOperationException. This signals an attempt to use a read-only projection as a writable struct.

Source

Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/RowDataWrapper.java:83

  }

  @Override
  public int size() {
    return types.length;
  }

  @Override
  public <T> T get(int pos, Class<T> javaClass) {
    if (rowData.isNullAt(pos)) {
      return null;
    }

    return javaClass.cast(getters[pos].get(rowData, pos));
  }

  @Override
  public <T> void set(int pos, T value) {
    throw new UnsupportedOperationException(
        "Could not set a field in the RowDataWrapper because rowData is read-only");
  }

  private interface PositionalGetter<T> {
    T get(RowData data, int pos);
  }

  private static PositionalGetter<?> buildGetter(LogicalType logicalType, Type type) {
    switch (logicalType.getTypeRoot()) {
      case TINYINT:
        return (row, pos) -> (int) row.getByte(pos);
      case SMALLINT:
        return (row, pos) -> (int) row.getShort(pos);
      case CHAR:
      case VARCHAR:
        return (row, pos) -> row.getString(pos).toString();

      case BINARY:

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Do not call set(); construct a new RowData with the desired values instead of mutating the wrapper
  2. Use a mutable StructLike implementation (e.g. a GenericRowData-backed wrapper or the write-path converter) for writing paths
  3. Refactor code to build output values via Flink RowData/converters rather than mutating the read wrapper

Example fix

// before
wrapper.set(2, newValue); // throws
// after
GenericRowData out = new GenericRowData(row.getArity());
for (int i = 0; i < row.getArity(); i++) out.setField(i, row.getField(i));
out.setField(2, newValue);
Defensive patterns

Strategy: type-guard

Validate before calling

if (structLike instanceof RowDataWrapper) { throw new IllegalArgumentException("RowDataWrapper is read-only; use a writable StructLike"); }

Type guard

boolean isWritable(StructLike s) { return !(s instanceof RowDataWrapper); }

Try / catch

try { wrapper.set(pos, v); } catch (UnsupportedOperationException e) { /* fall back to building a new GenericRowData */ }

Prevention

When it happens

Trigger: Calling RowDataWrapper.set(pos, value) on any position; passing a RowDataWrapper where a writable StructLike is expected (e.g. write paths that mutate struct fields in place).

Common situations: Reuse of read-side wrappers in a write path; generic code that treats StructLike as mutable; custom readers/writers built on top of RowDataWrapper that try to fill values in place.

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/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/4a5c282d7912b45d. Report an issue: GitHub.