{"record":{"id":"cae5447ae84bd42f","repo":"apache/iceberg","slug":"cannot-modify-getclass-getname","errorCode":null,"errorMessage":"Cannot modify ${getClass().getName()}","messagePattern":"Cannot modify (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/deletes/EmptyPositionDeleteIndex.java","lineNumber":38,"sourceCode":"\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\n  public String toString() {\n    return \"PositionDeleteIndex{}\";\n  }\n}\n","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/deletes/EmptyPositionDeleteIndex.java#L20-L56","documentation":"Same contract as error 763: the EmptyPositionDeleteIndex singleton's range delete(long posStart, long posEnd) throws UnsupportedOperationException because the instance is immutable and shared. It exists only to answer isDeleted() with false and iterate zero positions.","triggerScenarios":"Invoking delete(posStart, posEnd) on EmptyPositionDeleteIndex.get(), typically from a writer or merge path that received the singleton as its position-delete index for a file with no deletes.","commonSituations":"Custom merge-on-read code or DV handling that falls back to the empty index then attempts batch range deletes; tests exercising write paths against the singleton.","solutions":["Instantiate a concrete mutable index (BitmapPositionDeleteIndex) instead of using the singleton when writes are expected","Guard batch-delete code paths with a check for EmptyPositionDeleteIndex before calling delete","Use the index's merge() path with a mutable receiver if combining indexes","Fix initialization logic so write-capable code never receives the empty singleton"],"exampleFix":"// before\nEmptyPositionDeleteIndex.get().delete(0, 100); // UnsupportedOperationException\n// after\nPositionDeleteIndex idx = index instanceof EmptyPositionDeleteIndex\n    ? new BitmapPositionDeleteIndex()\n    : index;\nidx.delete(0, 100);","handlingStrategy":"type-guard","validationCode":"if (idx instanceof EmptyPositionDeleteIndex && needWrites) {\n  idx = new BitmapPositionDeleteIndex();\n}","typeGuard":"boolean supportsRangeDelete(PositionDeleteIndex idx) {\n  return !(idx instanceof EmptyPositionDeleteIndex);\n}","tryCatchPattern":"try {\n  idx.delete(start, end);\n} catch (UnsupportedOperationException e) {\n  // fallback to mutable index\n  idx = new BitmapPositionDeleteIndex();\n  idx.delete(start, end);\n}","preventionTips":["Never use the empty singleton as a write target","Range-delete code should construct a fresh index if handed the singleton","Unit-test write paths with a no-deletes table to catch singleton misuse","Document that EmptyPositionDeleteIndex is immutable"],"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-14T16:17:12.679Z"}