apache/iceberg · error · UnsupportedOperationException
this.getClass().getName() + does not implement insert
Error message
this.getClass().getName() + does not implement insert
What it means
This position-delete writer in SparkPositionDeltaWrite does not implement insert() — row insertion is handled by the paired data writer or via reinsert() in MoR variants. Calling insert() on this specific writer deliberately throws UnsupportedOperationException.
Source
Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkPositionDeltaWrite.java:650
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);
}
@Override
public void abort() throws IOException {
close();
DeleteWriteResult result = delegate.result();
SparkCleanupUtil.deleteTaskFiles(io, result.deleteFiles());
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Route inserted rows to the data writer (SparkWrite) rather than the position-delete writer.
- Use the MoR writer's reinsert()/insert() path when operating in merge-on-read mode.
- Upgrade Spark/Iceberg versions so the Delta execution plan routes inserts to the correct writer.
- If implementing a custom writer, override insert() with real logic.
Example fix
// before: insert on delete writer positionDeleteWriter.insert(row); // after: delegate to the data writer dataWriter.write(row);
Defensive patterns
Strategy: type-guard
Validate before calling
if (!(writer instanceof RowDataWriter)) { throw new IllegalArgumentException("Route inserts to the data writer"); } Type guard
boolean acceptsInsert(Object w) { return w instanceof IcebergWriter && !(w instanceof PositionDeleteWriter); } Try / catch
try { writer.insert(row); } catch (UnsupportedOperationException e) {
dataWriter.write(row); // route to the data writer
} Prevention
- Send inserted rows to the data writer, deletes to the position-delete writer
- Use reinsert() only on the MoR writer path
- Do not bypass Spark's Delta execution routing
When it happens
Trigger: Code calls insert(row) on the copy-on-write position-delete writer of SparkPositionDeltaWrite instead of routing new rows to the data writer or the MoR writer's reinsert path.
Common situations: Custom Delta integrations or refactors that funnel both deletes and inserts through the delete writer; internal API misuse when writing MERGE results manually.
Related errors
- Table does not implement %s: %s (%s)
- this.getClass().getName() + does not implement update
- Update must be represented as delete and insert
- Unsupported operation mode: + mode
- Unsupported command: + command
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/4463067fd57e2776.
Report an issue: GitHub.