{"record":{"id":"d09b38da84794e91","repo":"apache/iceberg","slug":"cannot-modify","errorCode":null,"errorMessage":"Cannot modify ","messagePattern":"Cannot modify ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/deletes/EmptyPositionDeleteIndex.java","lineNumber":33,"sourceCode":" * KIND, either express or implied.  See the License for the\n * specific language governing permissions and limitations\n * under the License.\n */\npackage org.apache.iceberg.deletes;\n\nclass EmptyPositionDeleteIndex implements PositionDeleteIndex {\n\n  private static final EmptyPositionDeleteIndex INSTANCE = new EmptyPositionDeleteIndex();\n\n  private EmptyPositionDeleteIndex() {}\n\n  static EmptyPositionDeleteIndex get() {\n    return INSTANCE;\n  }\n\n  @Override\n  public void delete(long position) {\n    throw new UnsupportedOperationException(\"Cannot modify \" + getClass().getName());\n  }\n\n  @Override\n  public void delete(long posStart, long posEnd) {\n    throw new UnsupportedOperationException(\"Cannot modify \" + getClass().getName());\n  }\n\n  @Override\n  public boolean isDeleted(long position) {\n    return false;\n  }\n\n  @Override\n  public boolean isEmpty() {\n    return true;\n  }\n\n  @Override","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/deletes/EmptyPositionDeleteIndex.java#L15-L51","documentation":"EmptyPositionDeleteIndex is an immutable singleton representing an empty position delete index. Calling delete(long) throws UnsupportedOperationException because the singleton must never be mutated; mutation would corrupt shared state used by any reader that received this instance.","triggerScenarios":"Calling EmptyPositionDeleteIndex.get().delete(pos) directly, or passing the singleton to code such as PositionDeleteIndex.merge that invokes delete() on it (e.g. DV-based indexes merging into an EmptyPositionDeleteIndex).","commonSituations":"Custom scan/delete-code paths that assume every PositionDeleteIndex is mutable; constructing read plans for tables with no position deletes then attempting to record new positions into the shared singleton.","solutions":["Replace the empty index with a real mutable index, e.g. new BitmapPositionDeleteIndex(), before recording positions","Never cache or reuse EmptyPositionDeleteIndex.get() as a write target","If merging, use an implementation that supports merge() instead of writing into the singleton","Audit custom delete-handling code to detect the empty-index singleton before mutation"],"exampleFix":"// before\nPositionDeleteIndex index = EmptyPositionDeleteIndex.get();\nindex.delete(position); // UnsupportedOperationException\n// after\nPositionDeleteIndex index = (existing == null || existing instanceof EmptyPositionDeleteIndex)\n    ? new BitmapPositionDeleteIndex()\n    : existing;\nindex.delete(position);","handlingStrategy":"type-guard","validationCode":"if (index instanceof EmptyPositionDeleteIndex) {\n  index = new BitmapPositionDeleteIndex();\n}","typeGuard":"static boolean isMutableIndex(PositionDeleteIndex idx) {\n  return !(idx instanceof EmptyPositionDeleteIndex);\n}","tryCatchPattern":"try {\n  index.delete(pos);\n} catch (UnsupportedOperationException e) {\n  throw new IllegalStateException(\"Attempted to mutate immutable empty index; use a concrete index\", e);\n}","preventionTips":["Treat EmptyPositionDeleteIndex.get() as read-only: only isDeleted/forEach","Create a mutable index whenever positions will be recorded","Never pass the singleton to code that writes positions","Review custom scan pipelines for shared-index reuse"],"tags":["unsupported-operation","immutable","position-delete","singleton"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}