apache/iceberg · error · UnsupportedOperationException

Cannot create TableScan from table of type POSITION_DELETES

Error message

Cannot create TableScan from table of type POSITION_DELETES

What it means

PositionDeletesTable is a metadata table exposing position delete files. It supports only batch scans, so TableScan.newScan() is intentionally unimplemented and throws UnsupportedOperationException. Callers must use the batch scan API instead.

Source

Thrown at core/src/main/java/org/apache/iceberg/PositionDeletesTable.java:80

  PositionDeletesTable(Table table) {
    this(table, table.name() + ".position_deletes");
  }

  PositionDeletesTable(Table table, String name) {
    super(table, name);
    this.schema = calculateSchema();
    this.defaultSpecId = table.spec().specId();
    this.specs = transformSpecs(schema(), table.specs());
  }

  @Override
  MetadataTableType metadataTableType() {
    return MetadataTableType.POSITION_DELETES;
  }

  @Override
  public TableScan newScan() {
    throw new UnsupportedOperationException(
        "Cannot create TableScan from table of type POSITION_DELETES");
  }

  @Override
  public BatchScan newBatchScan() {
    return new PositionDeletesBatchScan(table(), schema());
  }

  @Override
  public Schema schema() {
    return schema;
  }

  @Override
  public PartitionSpec spec() {
    return specs.get(defaultSpecId);
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Use PositionDeletesTable.newBatchScan() / BatchScan instead of newScan()
  2. Check table type before scanning: if the table is a metadata table (MetadataTableType.POSITION_DELETES), route to the batch scan API
  3. Cast to BatchScan: ((PositionDeletesTable) table).newBatchScan() and configure with .where()/project() equivalents on BatchScan

Example fix

// before
TableScan scan = table.newScan();
// after
BatchScan scan = ((PositionDeletesTable) table).newBatchScan();
Defensive patterns

Strategy: validation

Validate before calling

if (table instanceof PositionDeletesTable || MetadataTableUtils.metadataTableType(table) == MetadataTableType.POSITION_DELETES) {
  BatchScan scan = ((PositionDeletesTable) table).newBatchScan();
} else {
  TableScan scan = table.newScan();
}

Type guard

boolean supportsTableScan(Table t) { return !(t instanceof PositionDeletesTable); }

Try / catch

try { table.newScan(); } catch (UnsupportedOperationException e) { /* fall back to newBatchScan() */ }

Prevention

When it happens

Trigger: Calling newScan() (or table.scan()/TableScan-based refinement APIs) on a PositionDeletesTable instance obtained via MetastoreTables/MetadataTableUtils, e.g. scanning the 'tbl.position_deletes' metadata table through the streaming TableScan interface.

Common situations: Generic scan helper code that calls table.newScan() for any table without special-casing metadata tables; frameworks that default to TableScan; users assuming all Iceberg tables support incremental scans.

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/692de72ea69db3a6. Report an issue: GitHub.