{"record":{"id":"e4807184738a6927","repo":"microsoft/garnet","slug":"consistent-read-context-does-not-allow-reads-from","errorCode":null,"errorMessage":"Consistent read context does not allow reads from address!","messagePattern":"Consistent read context does not allow reads from address!","errorType":"exception","errorClass":"TsavoriteException","httpStatus":null,"severity":"error","filePath":"libs/storage/Tsavorite/cs/src/core/ClientSession/ConsistentReadContext.cs","lineNumber":112,"sourceCode":"            TOutput output = default;\n            return (Read(key, ref input, ref output, ref readOptions, userContext), output);\n        }\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public Status Read(TKey key, ref TInput input, ref TOutput output, ref ReadOptions readOptions, out RecordMetadata recordMetadata, TContext userContext = default)\n        {\n            var hash = readOptions.KeyHash ?? GetKeyHash(key);\n            Session.functions.PreSingleKeyConsistentRead(hash);\n            var status = BasicContext.Read(key, ref input, ref output, ref readOptions, out recordMetadata, userContext);\n            Session.functions.PostSingleKeyConsistentReadCallback();\n            return status;\n        }\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public Status ReadAtAddress(long address, ref TInput input, ref TOutput output, ref ReadOptions readOptions, out RecordMetadata recordMetadata, TContext userContext = default)\n            => throw new TsavoriteException(\"Consistent read context does not allow reads from address!\");\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public Status ReadAtAddress(long address, TKey key, ref TInput input, ref TOutput output, ref ReadOptions readOptions, out RecordMetadata recordMetadata, TContext userContext = default)\n            => throw new TsavoriteException(\"Consistent read context does not allow reads from address!\");\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void ReadWithPrefetch<TBatch>(ref TBatch batch, TContext userContext = default)\n            where TBatch : IReadArgBatch<TKey, TInput, TOutput>\n#if NET9_0_OR_GREATER\n            , allows ref struct\n#endif\n        {\n            do\n            {\n                Thread.Yield();\n                Session.functions.PreBatchKeyConsistentReadCallback(batch.Parameters);","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/storage/Tsavorite/cs/src/core/ClientSession/ConsistentReadContext.cs#L94-L130","documentation":"ConsistentReadContext provides sequential-read consistency by tracking read positions. ReadAtAddress reads a record at a specific logical address, which bypasses the consistent-read cursor/sequence tracking that guarantees you see a monotonic, coherent view of the store. Allowing address-based reads would break the consistency invariant, so both overloads throw.","triggerScenarios":"Calling consistentContext.ReadAtAddress(address, ref input, ...) — the single-address overload — on a ConsistentReadContext obtained from a session with enableConsistentRead=true.","commonSituations":"Enabling consistent reads on a session but then attempting address-based reads (e.g. for recovery, replay, or low-level record access); porting BasicContext.ReadAtAddress code to a consistent-read session.","solutions":["For address-based reads, use session.BasicContext.ReadAtAddress instead of ConsistentReadContext.ReadAtAddress.","If consistent reads are required, do not use ReadAtAddress — use key-based Read which respects the consistency cursor.","Create a separate session (without enableConsistentRead) for low-level address-based access."],"exampleFix":"// before\nvar status = session.ConsistentReadContext.ReadAtAddress(addr, ref input, ref output, ref opts, out var meta);\n\n// after\nvar status = session.BasicContext.ReadAtAddress(addr, ref input, ref output, ref opts, out var meta);","handlingStrategy":"validation","validationCode":"if (session.ConsistentReadContext is not null) throw new InvalidOperationException(\"Use BasicContext.ReadAtAddress for address-based reads; ConsistentReadContext disallows them.\");","typeGuard":"static bool CanReadAtAddress(ClientSession s) => !s.EnableConsistentRead;","tryCatchPattern":null,"preventionTips":["Do not enable consistent reads on sessions that need address-based access.","Use BasicContext.ReadAtAddress for low-level record reads.","Create a dedicated non-consistent session for recovery/replay address reads."],"tags":["tsavorite","session","consistent-read","read-at-address","api-misuse","csharp"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}