{"record":{"id":"da0694ddb3c9d821","repo":"dotnet/orleans","slug":"load-must-be-called-after-a-failed-store-before-th","errorCode":null,"errorMessage":"Load must be called after a failed Store before this storage instance can be reused.","messagePattern":"Load must be called after a failed Store before this storage instance can be reused\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/AWS/Orleans.Transactions.DynamoDB/TransactionalState/DynamoDBTransactionalStateStorage.cs","lineNumber":147,"sourceCode":"            var metadata = this.key.Metadata is { Length: > 0 }\n                ? this.ConvertFromStorageFormat<TransactionalStateMetaData>(this.key.Metadata)\n                : new TransactionalStateMetaData();\n            this.requiresReload = false;\n            return new TransactionalStorageLoadResponse<TState>(this.key.ETag.ToString(), committedState, this.key.CommittedSequenceId, metadata, PrepareRecordsToRecover);\n        }\n        catch (Exception ex)\n        {\n            this.logger.LogError(ex, \"Error loading transactional state for partition key {PartitionKey}\", this.partitionKey);\n            throw;\n        }\n    }\n\n    /// <inheritdoc />\n    public async Task<string> Store(string? expectedETag, TransactionalStateMetaData metadata, List<PendingTransactionState<TState>>? statesToPrepare, long? commitUpTo, long? abortAfter)\n    {\n        if (this.requiresReload)\n        {\n            throw new InvalidOperationException(\"Load must be called after a failed Store before this storage instance can be reused.\");\n        }\n\n        var batchOperation = new BatchOperation(this.storage, this.tableName, this.key, this.logger);\n        var keyWasNew = !this.key.ETag.HasValue;\n\n        try\n        {\n            var keyETag = key.ETag?.ToString();\n            if ((!string.IsNullOrWhiteSpace(keyETag) || !string.IsNullOrWhiteSpace(expectedETag)) &&\n                keyETag != expectedETag)\n            {\n                throw new ArgumentException(\"Etag does not match\", nameof(expectedETag));\n            }\n\n            var serializedMetadata = this.ConvertToStorageFormat(metadata);\n            var timestamp = DateTimeOffset.UtcNow;\n            var committedSequenceId = commitUpTo.HasValue && commitUpTo.Value > key.CommittedSequenceId\n                ? commitUpTo.Value","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/AWS/Orleans.Transactions.DynamoDB/TransactionalState/DynamoDBTransactionalStateStorage.cs#L129-L165","documentation":"Thrown by DynamoDBTransactionalStateStorage.Store when the requiresReload flag is still true. Store sets requiresReload = true at the start of its work because it mutates cached entities while building the batch; if that batch fails, the in-memory cache is left inconsistent. The contract is that after a failed Store the caller must call Load to rebuild the cache before reusing the instance. Calling Store again without Load violates that contract.","triggerScenarios":"A Store call failed (batch write error, size validation, etc.) and the same storage instance is reused for another Store without an intervening Load. The previous failure left requiresReload true to force a cache refresh.","commonSituations":"Retry loops that re-invoke Store on the same instance after a transient DynamoDB error; custom transaction participants that ignore Store failures and continue; tests that hammer Store without reloading.","solutions":["After any failed Store, call Load on the same instance before retrying Store.","In retry logic, structure as: try Store; on failure -> await Load(); then retry Store.","Do not catch-and-ignore Store failures; treat them as requiring a cache reload.","If Load also fails, surface the error rather than looping on Store."],"exampleFix":"// before\ntry { await store.Store(etag, meta, prep, commit, abort); }\ncatch { await store.Store(etag, meta, prep, commit, abort); } // throws: requiresReload\n\n// after\ntry { await store.Store(etag, meta, prep, commit, abort); }\ncatch\n{\n    await store.Load(); // restore consistent cache\n    await store.Store(etag, meta, prep, commit, abort); // safe to retry","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await store.Store(etag, meta, prep, commit, abort); }\ncatch (Exception ex) when (store is not null)\n{\n    logger.LogWarning(ex, \"Store failed; reloading cache before any retry.\");\n    var fresh = await store.Load();   // clears requiresReload\n    await store.Store(fresh.ETag, meta, prep, commit, abort);\n}","preventionTips":["After a failed Store, always call Load before retrying on the same instance.","Do not catch-and-ignore Store failures.","Structure retry as Store -> on failure Load -> Store.","Surface persistent Load failures instead of looping."],"tags":["aws","dynamodb","transactions","state-management","orleans"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}