dotnet/orleans · error · ArgumentOutOfRangeException
The collection must contain between 1 and {maxTransactionSiz
Error message
The collection must contain between 1 and {maxTransactionSize} rows. What it means
ArgumentOutOfRangeException from the internal CreateTableEntriesAsync: the collection must contain between 1 and maxTransactionSize (hard-coded 100) rows. Unlike BulkInsertTableEntries, this method rejects empty collections as well, because it builds a single TableTransactionAction list and a 0-row transaction is meaningless. The 100 cap matches Azure Table entity-group transaction limits.
Source
Thrown at src/Azure/Shared/Storage/AzureTableDataManager.cs:613
catch (Exception exc)
{
LogWarningBulkInsertTableEntries(Logger, exc, collection.Count, TableName);
}
}
finally
{
CheckAlertSlowAccess(startTime, operation);
}
}
internal async Task CreateTableEntriesAsync(IReadOnlyCollection<T> collection)
{
const string operation = "CreateTableEntries";
const int maxTransactionSize = 100;
ArgumentNullException.ThrowIfNull(collection);
if (collection.Count is 0 or > maxTransactionSize)
{
throw new ArgumentOutOfRangeException(
nameof(collection),
collection.Count,
$"The collection must contain between 1 and {maxTransactionSize} rows.");
}
var startTime = DateTime.UtcNow;
LogTraceTableEntriesCount(Logger, operation, collection.Count, TableName);
try
{
try
{
var transaction = new List<TableTransactionAction>(collection.Count);
foreach (var entry in collection)
{
transaction.Add(new TableTransactionAction(TableTransactionActionType.Add, entry));
}
await Table.SubmitTransactionAsync(transaction);View on GitHub (pinned to fca799fa70)
Solutions
- Guard empty collections before calling: if (entries.Count == 0) return; and chunk to <= 100 rows.
- Fix the chunking so no sub-batch exceeds 100 (use the same BatchIEnumerable(100) pattern used elsewhere in the file).
- Do not call CreateTableEntriesAsync for updates; it issues Create-only TableTransactionActions.
Example fix
// before
await mgr.CreateTableEntriesAsync(filtered); // throws if empty or >100
// after
if (filtered.Count == 0) return;
foreach (var batch in filtered.BatchIEnumerable(100))
await mgr.CreateTableEntriesAsync(batch); Defensive patterns
Strategy: validation
Validate before calling
if (collection.Count == 0) return;
foreach (var batch in collection.BatchIEnumerable(100))
await mgr.CreateTableEntriesAsync(batch); Type guard
static bool IsValidCreateBatch(IReadOnlyCollection<T> c) => c.Count is > 0 and <= 100;
Prevention
- Skip empty collections before the create path
- Chunk to the hard 100-row limit
- Use CreateTableEntriesAsync only for inserts, not updates
When it happens
Trigger: Calling CreateTableEntriesAsync with collection.Count == 0 or collection.Count > 100. Because it is internal, the trigger is usually another AzureTableDataManager method (e.g. a wrapper that forwards a caller's collection) receiving an empty or oversized input.
Common situations: A caller filters a list down to zero rows then forwards it to the create path, or a batch splitter produces a remainder chunk larger than 100 due to an off-by-one. Less commonly, a custom subclass calling the internal method directly.
Related errors
- Too many rows for bulk update - max {this.StoragePolicyOptio
- Unknown Playground:Storage:Provider value '{storageProvider}
- The table version entry must have a membership version.
- Value cannot be null. (Parameter 'clusterId')
- Table name "{tableName}" is invalid according to the followi
AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13).
Data as JSON: /api/errors/c1b459971a6f24b3.
Report an issue: GitHub.