{"record":{"id":"c913001faebffc8e","repo":"microsoft/garnet","slug":"failed-to-acquire-inprogress-lock-at-nameof-preba","errorCode":null,"errorMessage":"Failed to acquire inProgress lock at {nameof(PreBatchKeyConsistentReadCallback)}","messagePattern":"Failed to acquire inProgress lock at (.+?)","errorType":"exception","errorClass":"GarnetException","httpStatus":null,"severity":"error","filePath":"libs/server/AOF/ReadConsistency/ReplicaReadSessionContext.cs","lineNumber":201,"sourceCode":"                throw new GarnetException($\"Failed to acquire inProgress lock at {nameof(PostSingleKeyConsistentReadCallback)}\");\n            try\n            {\n                appendOnlyFile.readConsistencyManager.PostSingleKeyConsistentRead(ref replicaReadContext);\n            }\n            finally\n            {\n                inProgress.ReadUnlock();\n            }\n        }\n\n        /// <summary>\n        /// Initialize context for read key batch.\n        /// </summary>\n        /// <param name=\"parameters\"></param>\n        public void PreBatchKeyConsistentReadCallback(ReadOnlySpan<PinnedSpanByte> parameters)\n        {\n            if (!inProgress.TryReadLock())\n                throw new GarnetException($\"Failed to acquire inProgress lock at {nameof(PreBatchKeyConsistentReadCallback)}\");\n            try\n            {\n                var keyCount = parameters.Length;\n                var consistencyManager = appendOnlyFile.readConsistencyManager;\n                // First check if version of consistency manager has changed\n                appendOnlyFile.readConsistencyManager.CheckConsistencyManagerVersion(ref replicaReadContext);\n\n                // Allocate array to cache key hashes for batch read\n                if (keyHashCache == null || keyCount > keyHashCache.Length)\n                    ExpandKeyHashCache(keyCount);\n                else if ((keyCount << 2) < keyHashCache.Length)\n                    ShrinkKeyHashCache(keyCount);\n\n                // NOTE: this context is a copy used to emulate standalone reads.\n                // The actual update of the session max will happen after the read succeeds.\n                batchReadContext = replicaReadContext;\n                for (var i = 0; i < parameters.Length; i++)\n                {","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/server/AOF/ReadConsistency/ReplicaReadSessionContext.cs#L183-L219","documentation":"Thrown by ReplicaReadSessionContext.PreBatchKeyConsistentReadCallback when TryReadLock() on the 'inProgress' lock fails. This is the pre-read initialization for a batch of keys: it checks the consistency-manager version and caches key hashes. The read lock cannot be acquired because a writer (Dispose) currently holds it.","triggerScenarios":"A batch consistent read is initiated on a session that is concurrently being disposed, or a write lock is held due to re-entrancy. The non-blocking TryReadLock returns false and the method throws.","commonSituations":"Connection close / session teardown racing with a batch read request; a cancellation path disposing the session while the batch read callback is queued; a bug calling the batch read on a disposed session.","solutions":["Verify session liveness before issuing the batch read.","Catch GarnetException and return an error to the client (e.g. session closed).","Ensure dispose waits for all queued read callbacks to drain.","Add a disposed-flag guard at the start of the batch-read entry point."],"exampleFix":"// before\nsession.PreBatchKeyConsistentReadCallback(parameters);\n\n// after\nif (session.IsDisposed) return BatchReadResult.SessionClosed;\ntry { session.PreBatchKeyConsistentReadCallback(parameters); }\ncatch (GarnetException) { return BatchReadResult.SessionClosed; }","handlingStrategy":"try-catch","validationCode":"if (session.IsDisposed) return BatchReadResult.SessionClosed;\nsession.PreBatchKeyConsistentReadCallback(parameters);","typeGuard":null,"tryCatchPattern":"try { session.PreBatchKeyConsistentReadCallback(parameters); }\ncatch (GarnetException ex) when (ex.Message.Contains(\"inProgress lock\"))\n{ return BatchReadResult.SessionClosed; }","preventionTips":["Gate batch reads on session liveness.","Drain queued read callbacks before session disposal.","Correlate lock failures with dispose events in logs for diagnosis."],"tags":["aof","read-consistency","locking","replica","batch","internal"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}