{"record":{"id":"1f10d2675fdfceb6","repo":"microsoft/FASTER","slug":"lockable-method-call-when-beginlockable-has-not-been-called","errorCode":null,"errorMessage":"Lockable method call when BeginLockable has not been called","messagePattern":"Lockable method call when BeginLockable has not been called","errorType":"exception","errorClass":"FasterException","httpStatus":null,"severity":"error","filePath":"cs/src/core/ClientSession/ClientSession.cs","lineNumber":97,"sourceCode":"        internal void ReleaseLockable()\n        {\n            CheckIsAcquiredLockable();\n            if (TotalLockCount > 0)\n                throw new FasterException($\"EndLockable called with locks held: {sharedLockCount} shared locks, {exclusiveLockCount} exclusive locks\");\n            InternalReleaseLockable();\n        }\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        private void InternalReleaseLockable()\n        {\n            isAcquiredLockable = false;\n            fht.DecrementNumLockingSessions();\n        }\n\n        internal void CheckIsAcquiredLockable()\n        {\n            if (!isAcquiredLockable)\n                throw new FasterException(\"Lockable method call when BeginLockable has not been called\");\n        }\n\n        void CheckIsNotAcquiredLockable()\n        {\n            if (isAcquiredLockable)\n                throw new FasterException(\"BeginLockable cannot be called twice (call EndLockable first)\");\n        }\n\n        internal ClientSession(\n            FasterKV<Key, Value> fht,\n            FasterKV<Key, Value>.FasterExecutionContext<Input, Output, Context> ctx,\n            Functions functions,\n            SessionVariableLengthStructSettings<Value, Input> sessionVariableLengthStructSettings,\n            ILoggerFactory loggerFactory = null)\n        {\n            this.bContext = new(this);\n            this.uContext = new(this);\n","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/microsoft/FASTER/blob/321d872eabda6a0345c8bd76419f89723ed864ae/cs/src/core/ClientSession/ClientSession.cs#L79-L115","documentation":"CheckIsAcquiredLockable throws this FasterException when a lockable method (e.g. ReleaseLockable/EndLockable) is invoked before BeginLockable (AcquireLockable) established the session's lockable state. The isAcquiredLockable flag must be set by BeginLockable before any lockable operation is legal.","triggerScenarios":"Calling EndLockable/ReleaseLockable on a session on which AcquireLockable was never called, or calling it twice after the first EndLockable already cleared isAcquiredLockable.","commonSituations":"Lifecycle mistakes where EndLockable runs on a session just created or already finished; double-teardown of a session (two cleanup paths each calling EndLockable); copy/pasted cleanup code that assumes BeginLockable was executed elsewhere.","solutions":["Ensure AcquireLockable (BeginLockable) is called once before any EndLockable call on the session.","Track lockable state in application code (a bool) and skip EndLockable when not acquired.","Fix unbalanced begin/end pairs - one BeginLockable per EndLockable, in matched pairs.","Check exception paths: if the operation that should have called BeginLockable failed, don't run the release."],"exampleFix":"// before\nsession.ReleaseLockable(); // throws if BeginLockable never ran\n// after\nif (sessionAcquired)\n{\n    session.ReleaseLockable();\n    sessionAcquired = false;\n}","handlingStrategy":"validation","validationCode":"if (!sessionLockableAcquired) throw new InvalidOperationException(\"BeginLockable must be called before EndLockable\");","typeGuard":null,"tryCatchPattern":"try\n{\n    session.ReleaseLockable();\n}\ncatch (FasterException)\n{\n    // session was never acquired-lockable; skip teardown\n}","preventionTips":["Track a bool flag per session mirroring Begin/EndLockable state","Only call EndLockable in the same scope that called BeginLockable","Guard shared teardown/cleanup paths against double execution"],"tags":["locking","lifecycle","csharp"],"backgroundTag":"invalid-state-transition","analyzedSha":"321d872eabda6a0345c8bd76419f89723ed864ae","analyzedAt":"2026-09-15T22:18:00.693Z","contentChangedAt":"2026-09-15T22:18:00.693Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}