{"record":{"id":"8f69ef720b3f8b49","repo":"apache/iceberg","slug":"update-must-be-represented-as-delete-and-insert-8f69ef","errorCode":null,"errorMessage":"Update must be represented as delete and insert","messagePattern":"Update must be represented as delete and insert","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkPositionDeltaWrite.java","lineNumber":797,"sourceCode":"        SparkFileWriterFactory writerFactory,\n        OutputFileFactory dataFileFactory,\n        OutputFileFactory deleteFileFactory,\n        Function<InternalRow, InternalRow> rowLineageFromMetadata,\n        Context context) {\n      super(\n          table,\n          rewritableDeletes,\n          writerFactory,\n          dataFileFactory,\n          deleteFileFactory,\n          rowLineageFromMetadata,\n          context);\n      this.dataSpec = table.spec();\n    }\n\n    @Override\n    public void update(InternalRow meta, InternalRow id, InternalRow row) throws IOException {\n      throw new UnsupportedOperationException(\"Update must be represented as delete and insert\");\n    }\n\n    @Override\n    public void insert(InternalRow row) throws IOException {\n      reinsert(null, row);\n    }\n\n    @Override\n    public void reinsert(InternalRow meta, InternalRow row) throws IOException {\n      delegate.insert(decorateWithRowLineage(meta, row), dataSpec, null);\n    }\n  }\n\n  private static class PartitionedDeltaWriter extends DeleteAndDataDeltaWriter {\n    private final PartitionSpec dataSpec;\n    private final PartitionKey dataPartitionKey;\n    private final InternalRowWrapper internalRowDataWrapper;\n","sourceCodeStart":779,"sourceCodeEnd":815,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkPositionDeltaWrite.java#L779-L815","documentation":"The copy-on-write (delta data) writer of SparkPositionDeltaWrite represents every UPDATE as a delete of the old row plus an insert of the new row, per Delta protocol semantics. It throws UnsupportedOperationException from update() because in-place updates are never sent to this writer. If you see it, the execution layer tried an operation the Iceberg Spark integration cannot express.","triggerScenarios":"Spark Delta batch execution invokes update(meta, id, row) on the copy-on-write SparkPositionDeltaWrite instead of decomposing the update into delete+insert (e.g. a Spark version or custom plan that skips the split).","commonSituations":"Version mismatch between Spark's row-level operation APIs and the pinned iceberg-spark v4.0 module; custom physical plans calling update directly.","solutions":["Use a Spark version compatible with the iceberg-spark 4.0 module so updates are split into delete+insert.","Rewrite the command (MERGE/UPDATE) so it produces delete+insert, or run with the expected Spark Delta execution path.","If working around, implement a custom RowLevelOperation whose writer translates update into delete+reinsert."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"Preconditions.checkArgument(command instanceof Delete || command instanceof Update || command instanceof Merge, \"Only DELETE/UPDATE/MERGE are supported\");","typeGuard":null,"tryCatchPattern":"try { writer.update(meta, id, row); } catch (UnsupportedOperationException e) {\n  // rewrite operation as delete + insert\n  writer.delete(meta, id, oldRow); writer.insert(newRow);\n}","preventionTips":["Keep Spark and iceberg-spark module versions aligned","Express UPDATE/MERGE so the plan emits delete+insert pairs","Avoid custom physical plans calling writer.update directly"],"tags":["spark","copy-on-write","row-level-operations"],"backgroundTag":"operation-not-supported","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}