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 Flink RowData to Iceberg's StructLike for reading. Because RowData instances are read-only views over source data, set() is intentionally unsupported and always throws UnsupportedOperationException.

Solutions

  1. Use a mutable Iceberg Record (GenericRecord) or the writer-specific record class instead of RowDataWrapper for constructing data
  2. Only use RowDataWrapper in read paths (get); never call set
  3. Build a RowData via GenericRowData if you need to construct Flink-side records

Example fix

// before
RowDataWrapper w = ...; w.set(0, 42); // throws
// after
GenericRowData row = new GenericRowData(numFields); row.setField(0, 42);
Defensive patterns

Strategy: type-guard

Type guard

boolean isReadOnly(StructLike s) {
  return s instanceof RowDataWrapper;
}
// only call set() on mutable records (e.g. GenericRecord)

Try / catch

if (wrapper instanceof RowDataWrapper) {
  throw new IllegalStateException("RowDataWrapper is read-only; use GenericRecord for writes");
}
wrapper.set(pos, value);

Prevention

When it happens

Trigger: Calling .set(pos, value) on a RowDataWrapper obtained from wrapping a RowData record, e.g. code that assumes StructLike mutability (some Iceberg internal paths only read).

Common situations: Custom code reusing Iceberg StructLike wrappers to build or mutate records; accidentally passing a RowData-backed wrapper where an Iceberg Record/UpdatableRecord is expected by writer APIs.

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/50b5ac444acf0906. Report an issue: GitHub.

Appendix: source

Thrown at flink/v2.1/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)