apache/iceberg · error · UnsupportedOperationException

this.getClass().getName() + " does not implement update"

Error message

this.getClass().getName() + " does not implement update"

What it means

The writer used for Spark's position-delta row-level operations does not implement the update() operation of the DeltaWriter interface. Iceberg represents updates in Copy-on-Write/Merge-on-Read mode as a paired delete plus insert, so a direct row update is never supported by this writer class. The exception reports the concrete class name to identify which writer variant was invoked.

Solutions

  1. Do not call update() on this writer; emit a delete followed by an insert for the changed row.
  2. Ensure the row-level operation mode (write.merge/rewrite or copy-on-write settings) routes updates through the standard delete+insert path.
  3. If this arises from Spark itself, report it with the Spark/Iceberg version; it indicates an unexpected planner path.
  4. Upgrade to a newer Iceberg release where the delta write path may handle this differently.

Example fix

// before
writer.update(metadata, id, row);
// after
writer.delete(metadata, id);
writer.insert(row);
Defensive patterns

Strategy: try-catch

Validate before calling

if (deltaWriter instanceof PositionDeleteWriter) { throw new IllegalStateException("use delete+insert instead of update"); }

Try / catch

try { writer.update(meta, id, row); } catch (UnsupportedOperationException e) { writer.delete(meta, id); writer.insert(row); }

Prevention

When it happens

Trigger: Spark calls DeltaWriter.update(InternalRow metadata, InternalRow id, InternalRow row) on the position-delete-based writer inside SparkPositionDeltaWrite, e.g. when a row-level operation (UPDATE/MERGE/DELETE) attempts to route an updated row through update() instead of delete()+insert().

Common situations: Engine-internal code paths or custom Delta W handlers invoking update(); Spark planner changes routing updated rows directly; custom code reusing the writer API outside the normal delete+insert flow.

Related errors


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

Appendix: source

Thrown at spark/v4.1/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)