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

  1. Guard empty collections before calling: if (entries.Count == 0) return; and chunk to <= 100 rows.
  2. Fix the chunking so no sub-batch exceeds 100 (use the same BatchIEnumerable(100) pattern used elsewhere in the file).
  3. 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

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


AI-assisted analysis of dotnet/orleans@fca799fa70 (2026-08-13). Data as JSON: /api/errors/c1b459971a6f24b3. Report an issue: GitHub.