apache/iceberg · error · UnsupportedOperationException
${this.getClass().getName()} does not implement update
Error message
${this.getClass().getName()} does not implement update What it means
The position-delta writer delegates writes as delete files plus inserts; it has no path for in-place row updates. Spark's RowDataWriter update() entry point therefore throws UnsupportedOperationException identifying the concrete writer class.
Source
Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/SparkPositionDeltaWrite.java:609
@Override
public void delete(InternalRow metadata, InternalRow id) throws IOException {
int specId = metadata.getInt(specIdOrdinal);
PartitionSpec spec = specs.get(specId);
InternalRow partition = metadata.getStruct(partitionOrdinal, partitionRowWrapper.size());
StructProjection partitionProjection = partitionProjections.get(specId);
partitionProjection.wrap(partitionRowWrapper.wrap(partition));
String file = id.getString(fileOrdinal);
long position = id.getLong(positionOrdinal);
positionDelete.set(file, position);
delegate.write(positionDelete, spec, partitionProjection);
}
@Override
public void update(InternalRow metadata, InternalRow id, InternalRow row) {
throw new UnsupportedOperationException(
this.getClass().getName() + " does not implement update");
}
@Override
public void insert(InternalRow row) throws IOException {
throw new UnsupportedOperationException(
this.getClass().getName() + " does not implement insert");
}
@Override
public WriterCommitMessage commit() throws IOException {
close();
DeleteWriteResult result = delegate.result();
return new DeltaTaskCommit(result);
}
@OverrideView on GitHub (pinned to 86d9c8fc54)
Solutions
- Express updates as delete+insert (this is how the writer expects them; check the Spark action generating updates).
- Enable copy-on-write mode for the table so updates are supported: set write.update.mode=copy-on-write.
- Upgrade Iceberg/Spark integration to a version whose delta writer supports update operations if available.
Example fix
// before
UPDATE catalog.db.t SET c = 1 WHERE id = 5 // delta writer path
// after
ALTER TABLE catalog.db.t SET TBLPROPERTIES ('write.update.mode'='copy-on-write') Defensive patterns
Strategy: validation
Validate before calling
// ensure updates are supported for the table's write mode
String mode = table.properties().getOrDefault("write.update.mode", "merge-on-read");
boolean updatesSupported = "copy-on-write".equals(mode); Try / catch
try { writer.update(meta, id, row); } catch (UnsupportedOperationException e) { /* rewrite as delete+insert */ } Prevention
- Set write.update.mode=copy-on-write when UPDATE/MERGE updates are required
- Express updates as delete+insert in delta plans
- Confirm the Spark/Iceberg integration version supports updates for your write mode
When it happens
Trigger: A MERGE/position-delta write plan producing an 'update' operation (metadata + id + full row) routed to this writer, e.g. Spark emitting UPDATE rows through SparkWrite's position delta path.
Common situations: Running MERGE WHEN MATCHED THEN UPDATE (or UPDATE table) on a table configured for copy-on-write disabled / position-delta writes where the writer does not support update ops.
Related errors
- ${this.getClass().getName()} does not implement insert
- Update must be represented as delete and insert
- this.getClass().getName() + " does not implement insert"
- Cannot modify
- Cannot modify ${getClass().getName()}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/8e65e2b438ddd65f.
Report an issue: GitHub.