{"record":{"id":"b3871dcac53d3b44","repo":"apache/iceberg","slug":"max-concurrent-deletes-only-works-with-fileios-tha-b3871d","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/procedures/ExpireSnapshotsProcedure.java","lineNumber":150,"sourceCode":"        \"max_concurrent_deletes should have value > 0, value: %s\",\n        maxConcurrentDeletes);\n\n    return modifyIcebergTable(\n        tableIdent,\n        table -> {\n          ExpireSnapshots action = actions().expireSnapshots(table);\n\n          if (olderThanMillis != null) {\n            action.expireOlderThan(olderThanMillis);\n          }\n\n          if (retainLastNum != null) {\n            action.retainLast(retainLastNum);\n          }\n\n          if (maxConcurrentDeletes != null) {\n            if (table.io() instanceof SupportsBulkOperations) {\n              LOG.warn(\n                  \"max_concurrent_deletes only works with FileIOs that do not support bulk deletes. This \"\n                      + \"table is currently using {} which supports bulk deletes so the parameter will be ignored. \"\n                      + \"See that IO's documentation to learn how to adjust parallelism for that particular \"\n                      + \"IO's bulk delete.\",\n                  table.io().getClass().getName());\n            } else {\n\n              action.executeDeleteWith(executorService(maxConcurrentDeletes, \"expire-snapshots\"));\n            }\n          }\n\n          if (snapshotIds != null) {\n            for (long snapshotId : snapshotIds) {\n              action.expireSnapshotId(snapshotId);\n            }\n          }\n\n          if (streamResult != null) {","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/procedures/ExpireSnapshotsProcedure.java#L132-L168","documentation":"ExpireSnapshotsProcedure warns that the max_concurrent_deletes option only controls parallelism for FileIOs without bulk delete support. When the table's IO implements SupportsBulkOperations (e.g. S3FileIO), the option is ignored and the IO's own bulk-delete concurrency settings apply.","triggerScenarios":"Calling CALL iceberg.system.expire_snapshots(...) with max_concurrent_deletes set on a table whose io() instanceof SupportsBulkOperations.","commonSituations":"Users migrating configs from HadoopFileIO tables to S3/GCS tables keep max_concurrent_deletes and are surprised it no longer has effect.","solutions":["Remove max_concurrent_deletes and configure the IO's bulk-delete parallelism instead (e.g. S3FileIO delete batch size / thread pool properties)","Keep the option only for non-bulk IOs where it maps to executor threads","Check the FileIO implementation's documentation for its parallelism knobs"],"exampleFix":"// before\nCALL iceberg.system.expire_snapshots(table => 'db.t', max_concurrent_deletes => 16)\n// after\n-- set io-level property, e.g.\nALTER TABLE db.t SET TBLPROPERTIES ('io.manifest.cache-enabled'='true'); -- plus IO bulk-delete properties\nCALL iceberg.system.expire_snapshots(table => 'db.t')","handlingStrategy":"validation","validationCode":"if (maxConcurrentDeletes != null && table.io() instanceof SupportsBulkOperations) {\n  // skip passing max_concurrent_deletes; configure IO bulk-delete properties instead\n}","typeGuard":"boolean bulkSupported = table.io() instanceof SupportsBulkOperations;","tryCatchPattern":null,"preventionTips":["Check the table's FileIO type before setting max_concurrent_deletes","Use IO-native properties (e.g. S3FileIO bulk delete settings) for parallelism","Avoid copying HadoopFileIO-era tuning params to S3/GCS tables"],"tags":["spark","procedure","expire-snapshots","bulk-delete"],"backgroundTag":"ignored-config-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}