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
- Do not mutate SparkStructLike; build a new record/Row with the changed value instead.
- Use a mutable StructLike implementation (e.g. GenericsHelpers record) as the write target, then wrap it read-only with SparkStructLike for conversion.
- 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
- Never mutate rows returned by Iceberg scans; copy into a GenericData.Record first.
- Use mutable record implementations when accumulating/updating values.
- Keep SparkStructLike strictly on the read/conversion path.
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
- Cannot set fields in a TypeProjection
- Setting values is not supported
- Cannot update InternalRecordWrapper
- Not implemented: set
- Not implemented: set
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/70bca3fd63f46f7c.
Report an issue: GitHub.