{"record":{"id":"271867cff9883df4","repo":"microsoft/garnet","slug":"failed-to-acquire-inprogress-lock-at-nameof-presi","errorCode":null,"errorMessage":"Failed to acquire inProgress lock at {nameof(PreSingleKeyConsistentRead)}","messagePattern":"Failed to acquire inProgress lock at (.+?)","errorType":"exception","errorClass":"GarnetException","httpStatus":null,"severity":"error","filePath":"libs/server/AOF/ReadConsistency/ReplicaReadSessionContext.cs","lineNumber":164,"sourceCode":"        public void Dispose()\n        {\n            consistentReadCts.Cancel();\n            inProgress.WriteLock();\n            consistentReadCts.Dispose();\n            // batchReadContext shares the same waiter reference, so dispose it once here.\n            replicaReadContext.waiter?.Dispose();\n        }\n\n        /// <summary>\n        /// Freshness check before actual read for a single key\n        /// </summary>\n        /// <param name=\"hash\"></param>\n        /// <exception cref=\"GarnetException\"></exception>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void PreSingleKeyConsistentRead(long hash)\n        {\n            if (!inProgress.TryReadLock())\n                throw new GarnetException($\"Failed to acquire inProgress lock at {nameof(PreSingleKeyConsistentRead)}\");\n            try\n            {\n                appendOnlyFile.readConsistencyManager.PreSingleKeyConsistentRead(hash & long.MaxValue, ref replicaReadContext, readTimeout, consistentReadCts.Token);\n            }\n            finally\n            {\n                inProgress.ReadUnlock();\n            }\n        }\n\n        /// <summary>\n        /// Post read update maximum sequence number for a single key.\n        /// </summary>\n        /// <exception cref=\"GarnetException\"></exception>\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        public void PostSingleKeyConsistentReadCallback()\n        {\n            if (!inProgress.TryReadLock())","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/server/AOF/ReadConsistency/ReplicaReadSessionContext.cs#L146-L182","documentation":"Thrown by ReplicaReadSessionContext.PreSingleKeyConsistentRead when the internal SingleWriterMultiReaderLock 'inProgress' cannot be acquired for reading via TryReadLock(). TryReadLock fails when a writer currently holds the lock (e.g. Dispose is in progress, which takes a write lock). This is a session-lifecycle / concurrency error, not a data error.","triggerScenarios":"A consistent read is attempted on a replica read session that is concurrently being disposed (Dispose calls inProgress.WriteLock), or re-entrant access while a write lock is held. The read-path lock is non-blocking (Try, not Wait), so it throws immediately rather than waiting.","commonSituations":"A session is being torn down while in-flight reads are still active; a race between request cancellation/dispose and the read callback; a programming bug where PreSingleKeyConsistentRead is called after Dispose.","solutions":["Ensure the session is not disposed while reads are in flight — gate reads on session lifetime.","Guard the read call with a disposed-flag check before invoking PreSingleKeyConsistentRead.","Catch GarnetException at the call site and convert it to a client-readable error (e.g. 'session disposed').","Review shutdown ordering: complete pending reads before disposing the replica read session."],"exampleFix":"// before\nsession.PreSingleKeyConsistentRead(hash); // may throw if disposing\n\n// after\nif (session.IsDisposed) return ReadResult.SessionClosed;\ntry { session.PreSingleKeyConsistentRead(hash); }\ncatch (GarnetException) { return ReadResult.SessionClosed; }","handlingStrategy":"try-catch","validationCode":"// Guard against calling read methods on a disposing session\nif (session.IsDisposed) return ReadResult.SessionClosed;\nsession.PreSingleKeyConsistentRead(hash);","typeGuard":null,"tryCatchPattern":"try { session.PreSingleKeyConsistentRead(hash); }\ncatch (GarnetException ex) when (ex.Message.Contains(\"inProgress lock\"))\n{ /* session is disposing; abort the read gracefully */ return ReadResult.SessionClosed; }","preventionTips":["Track session disposed state and check it before read callbacks.","Drain in-flight reads before disposing the replica read session.","Review shutdown ordering to avoid dispose-while-reading races."],"tags":["aof","read-consistency","locking","replica","internal"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}