apache/iceberg · error · UnsupportedOperationException

Not implemented: set

Error message

Not implemented: set

What it means

SparkStructLike is a read-only wrapper that adapts an Iceberg StructLike row into Spark internal (Catalyst) values; get() converts values for reading, but mutation is intentionally unimplemented. Calling set(pos, value) always throws UnsupportedOperationException because rows produced for scanning are immutable views, not writable buffers.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/SparkStructLike.java:52

  public SparkStructLike wrap(Row row) {
    this.wrapped = row;
    return this;
  }

  @Override
  public int size() {
    return type.fields().size();
  }

  @Override
  public <T> T get(int pos, Class<T> javaClass) {
    Types.NestedField field = type.fields().get(pos);
    return javaClass.cast(SparkValueConverter.convert(field.type(), wrapped.get(pos)));
  }

  @Override
  public <T> void set(int pos, T value) {
    throw new UnsupportedOperationException("Not implemented: set");
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Do not mutate SparkStructLike; build a new record/Row with the changed value instead.
  2. Use a mutable StructLike implementation (e.g. GenericsHelpers record) as the write target, then wrap it read-only with SparkStructLike for conversion.
  3. If writing Spark rows, use the Spark writer APIs (SparkWrite) rather than mutating scan-produced structs.

Example fix

// before
sparkStructLike.set(pos, newValue); // throws UnsupportedOperationException
// after
GenericData.Record record = new GenericData.Record(sparkStructLike.structType());
for (int i = 0; i < record.size(); i++) record.set(i, sparkStructLike.get(i, Object.class));
record.set(pos, newValue);
Defensive patterns

Strategy: type-guard

Validate before calling

// treat SparkStructLike strictly as read-only in your code; never pass it where a mutable StructLike is required
if (structLike instanceof SparkStructLike) { /* read-only: do not call set */ }

Type guard

boolean isWritable = !(structLike instanceof SparkStructLike);

Try / catch

try {
  structLike.set(pos, value);
} catch (UnsupportedOperationException e) {
  if ("Not implemented: set".equals(e.getMessage())) { /* copy record and mutate the copy */ }
  else throw e;
}

Prevention

When it happens

Trigger: Any code path calling SparkStructLike.set(pos, value) — e.g. writing into the wrapped struct during upserts, merges, or generic code assuming a mutable StructLike.

Common situations: Custom merge/upsert logic that mutates rows in place; test harnesses reusing a StructLike instance as an accumulator; generic Iceberg code that writes to StructLike passed a Spark-backed wrapper.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/70bca3fd63f46f7c. Report an issue: GitHub.