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 variant that appends position deletes supports only write() of delete markers; Spark's RowDataWriter.update(metadata, id, row) contract for updating rows in place is not implemented and always throws UnsupportedOperationException. Updates to Iceberg tables must be expressed as a delete plus an insert.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/SparkPositionDeltaWrite.java:647

    @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);
    }

    @Override

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Ensure the Spark plan expresses updates as delete+insert (use Iceberg's standard UPDATE/MERGE support rather than calling update() on the writer)
  2. Use a writer implementation that supports updates (e.g. V2 copy-on-write path) if in-place update semantics are required
  3. Wrap the operation with Iceberg's procedures (CALL iceberg.system.merge/update) instead of custom writer code
Defensive patterns

Strategy: validation

Validate before calling

if (plan.requiresInPlaceUpdate()) {
  throw new IllegalArgumentException("Use delete+insert or copy-on-write path");
}

Prevention

When it happens

Trigger: Spark's MERGE/UPDATE execution invoking update() on the FanoutPositionDelete writer produced by SparkPositionDeltaWrite — i.e. a delta write plan that asks the position-delete delegate to update rows in place.

Common situations: Running UPDATE/MERGE statements whose plans attempt copy-on-write-style row updates through a position-delta (merge-on-read) writer; custom Spark sinks calling the wrong write method.

Related errors


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