dotnet/orleans · critical · InvalidOperationException

Storage state corrupted: no record for committed state v{thi

Error message

Storage state corrupted: no record for committed state v{this.key.CommittedSequenceId}

What it means

Thrown during DynamoDBTransactionalStateStorage.Load when key.CommittedSequenceId is non-zero but no matching state record exists in the loaded states list (FindState returns false). This indicates the persisted metadata points at a committed version that has no corresponding row, i.e., the transaction state table is inconsistent/corrupted for this partition. The provider logs a critical partition error before throwing InvalidOperationException.

Source

Thrown at src/AWS/Orleans.Transactions.DynamoDB/TransactionalState/DynamoDBTransactionalStateStorage.cs:89

                LogDebugLoadedV0Fresh(this.partitionKey);
                this.requiresReload = false;

                // first time load
                return new TransactionalStorageLoadResponse<TState>();
            }

            TState committedState;
            if (this.key.CommittedSequenceId == 0)
            {
                committedState = new TState();
            }
            else
            {
                if (!this.FindState(this.key.CommittedSequenceId, out var pos))
                {
                    var error = $"Storage state corrupted: no record for committed state v{this.key.CommittedSequenceId}";
                    LogCriticalPartitionError(this.partitionKey, error);
                    throw new InvalidOperationException(error);
                }

                committedState = this.ConvertFromStorageFormat<TState>(states[pos].Value);
            }

            var PrepareRecordsToRecover = new List<PendingTransactionState<TState>>();
            for (int i = 0; i < states.Count; i++)
            {
                var kvp = states[i];

                // pending states for already committed transactions can be ignored
                if (kvp.Key <= key.CommittedSequenceId)
                    continue;

                // upon recovery, local non-committed transactions are considered aborted
                if (kvp.Value.TransactionManager is null or { Length: 0 })
                    break;

View on GitHub (pinned to fca799fa70)

Solutions

  1. Restore the missing state row(s) for the committed sequence id from a consistent backup.
  2. If recovery is impossible, reset/clear the affected grain's transaction state (accept data loss) and let it reinitialize from v0.
  3. Stop all out-of-band processes that mutate the Orleans transaction state table.
  4. Verify backups are taken with DynamoDB point-in-time or on-demand backups that preserve cross-row consistency.
  5. File/examine an Orleans issue if this occurs without external tampering on a supported version.
Defensive patterns

Strategy: try-catch

Try / catch

try { var resp = await store.Load(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Storage state corrupted"))
{
    logger.LogCritical(ex, "Transaction state for partition {Key} is corrupted.", partitionKey);
    // escalate: quarantine the grain / restore from backup / reset state
    throw;
}

Prevention

When it happens

Trigger: Manual deletion or truncation of rows in the transaction state DynamoDB table; partial writes that committed metadata without the associated state entity; a failed/aborted migration; schema/version drift where older rows are missing; bugs in an upstream transaction layer leaving dangling CommittedSequenceId.

Common situations: Operator deleted DynamoDB items outside Orleans; table restored from a non-transactionally-consistent backup/point-in-time that split metadata and state rows; cross-version upgrade where the storage format changed and old rows were dropped; concurrent tools writing to the same table.

Related errors


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