apache/iceberg · error · UnsupportedOperationException

%s doesn't implement copyWithStats

Error message

%s doesn't implement copyWithStats

What it means

ContentFile.copyWithStats(Set<Integer>) is a default interface method that concrete File implementations must override to produce a copy filtered to the requested column stats. The default body throws UnsupportedOperationException naming the class that failed to implement it.

Source

Thrown at api/src/main/java/org/apache/iceberg/ContentFile.java:215

   * Copies this file without file stats. Manifest readers can reuse file instances; use this method
   * to copy data without stats when collecting files.
   *
   * @return a copy of this data file, without lower bounds, upper bounds, value counts, null value
   *     counts, nan value counts, or average value sizes
   */
  F copyWithoutStats();

  /**
   * Copies this file with column stats only for specific columns. Manifest readers can reuse file
   * instances; use this method to copy data with stats only for specific columns when collecting
   * files.
   *
   * @param requestedColumnIds column IDs for which to keep stats.
   * @return a copy of data file, with lower bounds, upper bounds, value counts, null value counts,
   *     nan value counts, and average value sizes for only specific columns.
   */
  default F copyWithStats(Set<Integer> requestedColumnIds) {
    throw new UnsupportedOperationException(
        this.getClass().getName() + " doesn't implement copyWithStats");
  }

  /**
   * Copies this file (potentially without file stats). Manifest readers can reuse file instances;
   * use this method to copy data when collecting files from tasks.
   *
   * @param withStats Will copy this file without file stats if set to <code>false</code>.
   * @return a copy of this data file. If <code>withStats</code> is set to <code>false</code> the
   *     file will not contain lower bounds, upper bounds, value counts, null value counts, nan
   *     value counts, or average value sizes
   */
  default F copy(boolean withStats) {
    return withStats ? copy() : copyWithoutStats();
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Upgrade iceberg-core/parquet modules so a full implementation (e.g. GenericDataFile) is used and consistent with iceberg-api.
  2. If you wrote a custom ContentFile implementation, implement copyWithStats to copy the file while filtering lower/upper bounds, value counts, null/nan counts, and avg sizes to requestedColumnIds.
  3. In tests, use real implementations (GenericDataFile.copy) rather than partial stubs.

Example fix

// before
class MyDataFile implements DataFile { /* no copyWithStats */ }

// after
@Override
public MyDataFile copyWithStats(Set<Integer> requestedColumnIds) {
  MyDataFile copy = copy();
  copy.setColumnStats filtered to requestedColumnIds;
  return copy;
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(file instanceof GenericDataFile)) {
  // may not implement copyWithStats — use file.copy() or upgrade
}

Try / catch

DataFile copy;
try {
  copy = file.copyWithStats(colIds);
} catch (UnsupportedOperationException e) {
  copy = file.copy(); // degrade: full copy without stat filtering
}

Prevention

When it happens

Trigger: Calling copyWithStats on a ContentFile implementation (custom, mock, or older library version) that has not overridden copyWithStats; using a DataFile built by hand rather than from a manifest reader.

Common situations: Custom FileIO/engine integrations subclassing a base file class that predates copyWithStats; test mocks returning plain DataFile instances; version skew between iceberg-api and iceberg-core jars.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/b1c8bef2dc3928f7. Report an issue: GitHub.