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

  1. Route inserted rows to the data writer (SparkWrite) rather than the position-delete writer.
  2. Use the MoR writer's reinsert()/insert() path when operating in merge-on-read mode.
  3. Upgrade Spark/Iceberg versions so the Delta execution plan routes inserts to the correct writer.
  4. 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

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


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