{"record":{"id":"34427ff66c134e83","repo":"microsoft/garnet","slug":"transactional-consistent-read-context-does-not-ref","errorCode":null,"errorMessage":"Transactional consistent read context does not Refresh!","messagePattern":"Transactional consistent read context does not Refresh!","errorType":"exception","errorClass":"TsavoriteException","httpStatus":null,"severity":"error","filePath":"libs/storage/Tsavorite/cs/src/core/ClientSession/TransactionalConsistentReadContext.cs","lineNumber":393,"sourceCode":"\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public Status Delete(TKey key, ref DeleteOptions deleteOptions, TContext userContext = default)\n            => throw new TsavoriteException(\"Transactional consistent read context does not allow writes!\");\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void ResetModified(TKey key)\n            => throw new TsavoriteException(\"Transactional consistent read context does not reset ResetModified!\");\n\n        /// <inheritdoc/>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        internal bool IsModified(TKey key)\n            => throw new TsavoriteException(\"Transactional consistent read context does not allow IsModified!\");\n\n        /// <inheritdoc/>\n        public void Refresh()\n            => throw new TsavoriteException(\"Transactional consistent read context does not Refresh!\");\n\n        #endregion ITsavoriteContext\n    }\n}","sourceCodeStart":375,"sourceCodeEnd":397,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/storage/Tsavorite/cs/src/core/ClientSession/TransactionalConsistentReadContext.cs#L375-L397","documentation":"Refresh (line 393) throws on TransactionalConsistentReadContext with 'does not Refresh!'. Refresh re-resolves the session's cached page pointers against the live log (epoch-protected); a consistent read context deliberately holds a stable snapshot, so forcing a refresh would break read consistency and is rejected. Use the write-capable contexts for Refresh.","triggerScenarios":"Calling tcrContext.Refresh() on the transactional consistent read context, e.g. to refresh record pointers after long-running pending I/O while still inside the consistent read scope.","commonSituations":"A long-lived consistent-read session tries to call Refresh (copied from a BasicContext/UnsafeContext pattern) to refresh in-memory pointers; the read-only context forbids it to preserve snapshot consistency.","solutions":["Call Refresh on a write-capable context: TransactionalUnsafeContext.Refresh (TransactionalUnsafeContext.cs:507), or BasicContext/UnsafeContext.","For a transactional consistent read, end and re-begin the transaction to get a fresh snapshot instead of calling Refresh.","Avoid holding a consistent read context across pointer-invalidating events."],"exampleFix":"// before\nvar tcr = session.TransactionalConsistentReadContext;\ntcr.Refresh(); // throws\n\n// after — refresh via a write-capable context, or restart the read snapshot\ntcr.EndTransaction();\ntcr.BeginTransaction(); // fresh consistent snapshot\n\n// or, on the unsafe transactional context:\n// var luc = session.TransactionalUnsafeContext;\n// luc.BeginUnsafe();\n// try { luc.Refresh(); } finally { luc.EndUnsafe(); }","handlingStrategy":"validation","validationCode":"// Do not Refresh on the read-only snapshot; refresh via a write-capable context, or restart the snapshot.\nvar w = session.TransactionalUnsafeContext;\nw.BeginUnsafe();\ntry { w.Refresh(); }\nfinally { w.EndUnsafe(); }\n// Or for a fresh consistent read: tcr.EndTransaction(); tcr.BeginTransaction();","typeGuard":"static bool IsReadOnlyContext<TCtx>() => typeof(TCtx).Name.Contains(\"ConsistentReadContext\");\n// Assert before any Refresh() call.","tryCatchPattern":null,"preventionTips":["Refresh re-resolves pointers against the live log; read-only snapshots intentionally forbid it.","Call Refresh on BasicContext/UnsafeContext/TransactionalUnsafeContext.","To refresh a consistent read, end and re-begin the transaction instead."],"tags":["tsavorite","transaction","read-only-context","refresh","snapshot","csharp"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}