apache/iceberg · warning
max_concurrent_deletes only works with FileIOs that do not s
Error message
max_concurrent_deletes only works with FileIOs that do not support bulk deletes. This table is currently using {} which supports bulk deletes so the parameter will be ignored. See that IO's documentation to learn how to adjust parallelism for that particular IO's bulk delete. What it means
A LOG.warn in ExpireSnapshotsProcedure.call: the max_concurrent_deletes parameter only controls thread pool size for FileIO implementations without bulk-delete support. When the table's FileIO implements SupportsBulkOperations (e.g. S3FileIO, GCSFileIO), parallelism is governed by the IO's own bulk-delete configuration and the procedure parameter is ignored.
Source
Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/procedures/ExpireSnapshotsProcedure.java:150
"max_concurrent_deletes should have value > 0, value: %s",
maxConcurrentDeletes);
return modifyIcebergTable(
tableIdent,
table -> {
ExpireSnapshots action = actions().expireSnapshots(table);
if (olderThanMillis != null) {
action.expireOlderThan(olderThanMillis);
}
if (retainLastNum != null) {
action.retainLast(retainLastNum);
}
if (maxConcurrentDeletes != null) {
if (table.io() instanceof SupportsBulkOperations) {
LOG.warn(
"max_concurrent_deletes only works with FileIOs that do not support bulk deletes. This "
+ "table is currently using {} which supports bulk deletes so the parameter will be ignored. "
+ "See that IO's documentation to learn how to adjust parallelism for that particular "
+ "IO's bulk delete.",
table.io().getClass().getName());
} else {
action.executeDeleteWith(executorService(maxConcurrentDeletes, "expire-snapshots"));
}
}
if (snapshotIds != null) {
for (long snapshotId : snapshotIds) {
action.expireSnapshotId(snapshotId);
}
}
if (streamResult != null) {View on GitHub (pinned to 86d9c8fc54)
Solutions
- Remove max_concurrent_deletes for tables using bulk-capable IOs; it has no effect.
- Tune the IO's own bulk-delete parallelism instead — e.g. S3FileIO's spark.s3.delete.batch-size / s3.delete.batch-size properties and the underlying client's concurrency settings.
- Consult the specific FileIO implementation's documentation for its bulk-delete concurrency knobs.
Example fix
// before
CALL catalog.system.expire_snapshots(table => 'db.t', max_concurrent_deletes => 20)
-- table io = S3FileIO (bulk deletes)
// after
CALL catalog.system.expire_snapshots(table => 'db.t')
-- tune IO instead: SET TABLE PROPERTIES ('s3.delete.batch-size'='...') or client config Defensive patterns
Strategy: validation
Validate before calling
if (table.io() instanceof SupportsBulkOperations) {
// do not pass max_concurrent_deletes; tune IO bulk-delete settings instead
} Type guard
boolean ioSupportsBulkDeletes = table.io() instanceof org.apache.iceberg.io.SupportsBulkOperations;
Prevention
- Conditionally pass max_concurrent_deletes only for non-bulk FileIOs
- Learn your IO's bulk-delete concurrency knobs (e.g. s3.delete.batch-size)
- Audit procedure call templates when migrating between FileIO implementations
When it happens
Trigger: CALL catalog.system.expire_snapshots(..., max_concurrent_deletes => N) on a table whose io() instanceof SupportsBulkOperations (e.g. S3FileIO).
Common situations: Migrating from HadoopFileIO to S3FileIO and carrying over old tuning options; copy-pasted procedure calls across tables with different IOs.
Related errors
- max_concurrent_deletes only works with FileIOs that do not s
- max_concurrent_deletes only works with FileIOs that do not s
- max_concurrent_deletes only works with FileIOs that do not s
- max_concurrent_deletes only works with FileIOs that do not s
- Deleted only {} of {} files using bulk deletes
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/a2235ec09e896564.
Report an issue: GitHub.