dotnet/orleans · error · InconsistentStateException

Could not load a consistent Azure Table transactional state

Error message

Could not load a consistent Azure Table transactional state snapshot.

What it means

Thrown by AzureTableTransactionalStateStorage when a consistent read of the transactional snapshot cannot be obtained: the etag (version) read before and after paginated reads differs, indicating a concurrent write during the load. Wraps the conflict as an InconsistentStateException with stored vs current etags.

Source

Thrown at src/Azure/Orleans.Transactions.AzureStorage/TransactionalState/AzureTableTransactionalStateStorage.cs:297

                    return (keyBefore, loadedStates);
                }

                if (versionBefore is null && versionAfter is null)
                {
                    // Legacy partitions do not have boundary rows. During rolling upgrades, older
                    // writers also leave existing boundaries stale, so torn reads remain allowed
                    // until every writer is upgraded to advance them.
                    return (keyBefore, loadedStates);
                }

                if (versionBefore is not null
                    && string.Equals(versionBefore, versionAfter, StringComparison.Ordinal))
                {
                    return (keyBefore, loadedStates);
                }
            }

            throw new InconsistentStateException(
                "Could not load a consistent Azure Table transactional state snapshot.",
                storedEtag: versionBefore ?? "null",
                currentEtag: versionAfter ?? "null");
        }

        private async Task<(
            KeyEntity Key,
            List<KeyValuePair<long, StateEntity>> States,
            bool IsPaginated,
            string? LowerBoundaryVersion,
            string? UpperBoundaryVersion)> ReadSnapshot()
        {
            var query = AzureTableUtils.RangeQuery(this.partition, LowerBoundaryRowKey, UpperBoundaryRowKey);
            var key = CreateFreshKey();
            var states = new List<KeyValuePair<long, StateEntity>>();
            var pageCount = 0;
            string? lowerBoundaryVersion = null;
            string? upperBoundaryVersion = null;

View on GitHub (pinned to fca799fa70)

Solutions

  1. Retry the transactional operation; the runtime typically re-drives the grain call.
  2. Reduce write contention / co-locate related grains to lower cross-partition races.
  3. Ensure pagination boundaries are advanced (newer Orleans versions tighten torn-read protection).
Defensive patterns

Strategy: retry

Try / catch

try { await storage.Load(); }
catch (InconsistentStateException) { await Task.Delay(backoff); await storage.Load(); }

Prevention

When it happens

Trigger: A writer commits to the partition between the pre- and post-read version checks during LoadSnapshot; pagination across multiple table segments amplifies the race window.

Common situations: High write contention on a transactional grain; large state forcing multi-page reads; concurrent activations.

Related errors


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