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
When expiring snapshots, max_concurrent_deletes only tunes delete parallelism for FileIOs that delete files one-by-one. If the table's IO implements SupportsBulkOperations (e.g. S3FileIO, GCSFileIO), the parameter is ignored and this is logged.
Source
Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/procedures/ExpireSnapshotsProcedure.java:145
"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 from the procedure call
- Tune the bulk-delete parallelism via the specific FileIO's own properties (e.g. s3.delete.batch-size / filesystem concurrency settings)
- Use a FileIO without bulk-delete support only if you need max_concurrent_deletes to take effect
Example fix
// before CALL iceberg.system.expire_snapshots(table => 'db.t', max_concurrent_deletes => 20) -- after CALL iceberg.system.expire_snapshots(table => 'db.t') -- plus e.g. s3.delete.batch-size in table properties
Defensive patterns
Strategy: validation
Validate before calling
if (table.io() instanceof org.apache.iceberg.io.SupportsBulkOperations) { /* don't pass max_concurrent_deletes */ } Type guard
boolean bulkDeletes = table.io() instanceof org.apache.iceberg.io.SupportsBulkOperations;
Prevention
- Check the table's FileIO class before setting max_concurrent_deletes
- Configure bulk-delete parallelism via IO-specific properties
- Read the warning's IO class name and consult its docs
When it happens
Trigger: CALL iceberg.system.expire_snapshots(...) with max_concurrent_deletes set while table.io() instanceof SupportsBulkOperations.
Common situations: Users tune thread counts assuming the setting applies to S3/GCS/Azure bulk deletes; those IOs control bulk-delete parallelism via their own properties (e.g. s3.delete.batch-size, concurrency settings).
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- max_concurrent_deletes only works with FileIOs that do not s
- max_concurrent_deletes only works with FileIOs that do not s
- Invalid value for ${SparkSQLProperties.VIEW_SCHEMA_BINDING_M
- Invalid value for ${SparkSQLProperties.VIEW_SCHEMA_BINDING_M
- max_concurrent_deletes only works with FileIOs that do not s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/5f31d558f8c039fd.
Report an issue: GitHub.