{"record":{"id":"41c3d3bbef32ed48","repo":"dotnet/orleans","slug":"too-many-rows-for-bulk-delete-max-this-storagep","errorCode":null,"errorMessage":"Too many rows for bulk delete - max {this.StoragePolicyOptions.MaxBulkUpdateRows}","messagePattern":"Too many rows for bulk delete - max (.+?)","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Azure/Shared/Storage/AzureTableDataManager.cs","lineNumber":473,"sourceCode":"        }\n\n        /// <summary>\n        /// Deletes a set of already existing data entries in the table, by using eTag.\n        /// Fails if the data does not already exist or if eTag does not match.\n        /// </summary>\n        /// <param name=\"collection\">Data entries and their corresponding etags to be deleted from the table.</param>\n        /// <returns>Completion promise for this storage operation.</returns>\n        public async Task DeleteTableEntriesAsync(List<(T Entity, string ETag)> collection)\n        {\n            const string operation = \"DeleteTableEntries\";\n            var startTime = DateTime.UtcNow;\n            LogTraceTableEntries(Logger, operation, new(collection), TableName);\n\n            if (collection == null) throw new ArgumentNullException(nameof(collection));\n\n            if (collection.Count > this.StoragePolicyOptions.MaxBulkUpdateRows)\n            {\n                throw new ArgumentOutOfRangeException(nameof(collection), collection.Count,\n                        \"Too many rows for bulk delete - max \" + this.StoragePolicyOptions.MaxBulkUpdateRows);\n            }\n\n            if (collection.Count == 0)\n            {\n                return;\n            }\n\n            try\n            {\n                var entityBatch = new List<TableTransactionAction>();\n                foreach (var tuple in collection)\n                {\n                    T item = tuple.Entity;\n                    item.ETag = new ETag(tuple.ETag);\n                    entityBatch.Add(new TableTransactionAction(TableTransactionActionType.Delete, item, item.ETag));\n                }\n","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/Azure/Shared/Storage/AzureTableDataManager.cs#L455-L491","documentation":"Thrown by AzureTableDataManager.DeleteTableEntriesAsync when the collection size exceeds StoragePolicyOptions.MaxBulkUpdateRows (default 100). Azure Table entity-group transactions are limited to 100 entities and must share a partition, so Orleans caps the batch and rejects larger inputs with an ArgumentOutOfRangeException carrying the offending count.","triggerScenarios":"Passing more than MaxBulkUpdateRows entries to DeleteTableEntriesAsync in one call; raising the number of deletables without chunking; lowering MaxBulkUpdateRows below an existing batch size.","commonSituations":"Bulk grain-state cleanup or reminder purge that gathers many rows; large partition scans producing big delete sets; tuning MaxBulkUpdateRows for other operations.","solutions":["Chunk the collection into batches of at most MaxBulkUpdateRows before calling DeleteTableEntriesAsync.","If appropriate for your workload, raise MaxBulkUpdateRows — but never above 100 (the Azure Table transaction limit).","Ensure all entities in a batch share the same PartitionKey (Azure entity-group transaction requirement)."],"exampleFix":"// before\nawait manager.DeleteTableEntriesAsync(allEntries); // allEntries.Count > 100 -> throws\n// after\nconst int BatchSize = 100; // <= options.StoragePolicyOptions.MaxBulkUpdateRows\nforeach (var batch in allEntries.Chunk(BatchSize).Select(c => c.ToList()))\n{\n    await manager.DeleteTableEntriesAsync(batch);\n}","handlingStrategy":"validation","validationCode":"int cap = Math.Min(100, options.StoragePolicyOptions.MaxBulkUpdateRows);\nforeach (var batch in collection.Chunk(cap).Select(c => c.ToList()))\n    await manager.DeleteTableEntriesAsync(batch);","typeGuard":"static bool WithinLimit(int count, int max) => count <= max;","tryCatchPattern":"catch (ArgumentOutOfRangeException ex) when (ex.Message.Contains(\"Too many rows for bulk delete\")) { /* chunk into batches <= MaxBulkUpdateRows, same partition */ }","preventionTips":["Always chunk bulk deletes to <= MaxBulkUpdateRows (<=100).","Ensure each batch shares one PartitionKey.","Adjust MaxBulkUpdateRows only within Azure's 100-entity limit."],"tags":["orleans","azure-storage","azure-table","batch","argument","limits"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}