apache/iceberg · error · UnsupportedOperationException
Cannot modify
Error message
Cannot modify ${getClass().getName()} What it means
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.
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
Example fix
// before
EmptyPositionDeleteIndex.get().delete(0, 100); // UnsupportedOperationException
// after
PositionDeleteIndex idx = index instanceof EmptyPositionDeleteIndex
? new BitmapPositionDeleteIndex()
: index;
idx.delete(0, 100); Defensive patterns
Strategy: type-guard
Validate before calling
if (idx instanceof EmptyPositionDeleteIndex && needWrites) {
idx = new BitmapPositionDeleteIndex();
} Type guard
boolean supportsRangeDelete(PositionDeleteIndex idx) {
return !(idx instanceof EmptyPositionDeleteIndex);
} Try / catch
try {
idx.delete(start, end);
} catch (UnsupportedOperationException e) {
// fallback to mutable index
idx = new BitmapPositionDeleteIndex();
idx.delete(start, end);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/cae5447ae84bd42f.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/deletes/EmptyPositionDeleteIndex.java:38
class EmptyPositionDeleteIndex implements PositionDeleteIndex {
private static final EmptyPositionDeleteIndex INSTANCE = new EmptyPositionDeleteIndex();
private EmptyPositionDeleteIndex() {}
static EmptyPositionDeleteIndex get() {
return INSTANCE;
}
@Override
public void delete(long position) {
throw new UnsupportedOperationException("Cannot modify " + getClass().getName());
}
@Override
public void delete(long posStart, long posEnd) {
throw new UnsupportedOperationException("Cannot modify " + getClass().getName());
}
@Override
public boolean isDeleted(long position) {
return false;
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public String toString() {
return "PositionDeleteIndex{}";
}
}
View on GitHub (pinned to 86d9c8fc54)