apache/iceberg · error · UnsupportedOperationException

Cannot delete from a

Error message

Cannot delete from a %s table

What it means

BaseReadOnlyTable disables all row mutation, including deletes. newDelete() unconditionally throws UnsupportedOperationException because a read-only table descriptor has no commit path to rewrite or delete data files.

Solutions

  1. Load a writable table via catalog.loadTable(identifier) before invoking newDelete().
  2. Check the table handle type/capability before issuing deletes.
  3. Perform deletes on the real table and use snapshot references only for reads.

Example fix

// before
readOnlyTable.newDelete().deleteFromRowFilter(expr).commit();
// after
Table table = catalog.loadTable(tableIdentifier);
table.newDelete().deleteFromRowFilter(expr).commit();
Defensive patterns

Strategy: validation

Validate before calling

if (!(table instanceof BaseReadOnlyTable)) {
  table.newDelete().deleteFromRowFilter(expr).commit();
}

Type guard

boolean isWritable(Table t) { return !(t instanceof BaseReadOnlyTable); }

Try / catch

try { table.newDelete()...commit(); } catch (UnsupportedOperationException e) { throw new IllegalStateException("Cannot delete via read-only handle", e); }

Prevention

When it happens

Trigger: Calling table.newDelete() (DeleteFiles API) on a read-only table instance such as a snapshot wrapper or metadata-backed table.

Common situations: Generic maintenance code (row-level deletes, GDPR-style deletes) applied to a table handle obtained from a snapshot or metadata table; copy-on-write engines acquiring a table handle through read-only APIs.

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/533f260f2efeb239. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/BaseReadOnlyTable.java:94

  public OverwriteFiles newOverwrite() {
    throw new UnsupportedOperationException("Cannot overwrite in a " + descriptor + " table");
  }

  @Override
  public RowDelta newRowDelta() {
    throw new UnsupportedOperationException(
        "Cannot remove or replace rows in a " + descriptor + " table");
  }

  @Override
  public ReplacePartitions newReplacePartitions() {
    throw new UnsupportedOperationException(
        "Cannot replace partitions in a " + descriptor + " table");
  }

  @Override
  public DeleteFiles newDelete() {
    throw new UnsupportedOperationException("Cannot delete from a " + descriptor + " table");
  }

  @Override
  public UpdateStatistics updateStatistics() {
    throw new UnsupportedOperationException(
        "Cannot update statistics of a " + descriptor + " table");
  }

  @Override
  public UpdatePartitionStatistics updatePartitionStatistics() {
    throw new UnsupportedOperationException(
        "Cannot update partition statistics of a " + descriptor + " table");
  }

  @Override
  public ExpireSnapshots expireSnapshots() {
    throw new UnsupportedOperationException(
        "Cannot expire snapshots from a " + descriptor + " table");

View on GitHub (pinned to 86d9c8fc54)