{"record":{"id":"3261c4eda04bb833","repo":"microsoft/garnet","slug":"exceeded-maximum-number-of-active-lightepoch-insta","errorCode":null,"errorMessage":"Exceeded maximum number of active LightEpoch instances {ActiveInstanceCount()} {InstanceIndexBuffer.MaxInstances}","messagePattern":"Exceeded maximum number of active LightEpoch instances (.+?) (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"libs/client/LightEpoch.cs","lineNumber":197,"sourceCode":"            CurrentEpoch = 1;\n            SafeToReclaimEpoch = 0;\n\n            // Mark all epoch table entries as \"available\"\n            for (int i = 0; i < kDrainListSize; i++)\n                drainList[i].epoch = long.MaxValue;\n            drainCount = 0;\n        }\n\n        int SelectInstance()\n        {\n            for (var i = 0; i < InstanceIndexBuffer.MaxInstances; i++)\n            {\n                ref var entry = ref InstanceTracker.GetRef(i);\n                // Try to claim this instance ID (indicated as 1 in the entry)\n                if (kInvalidIndex == Interlocked.CompareExchange(ref entry, 1, kInvalidIndex))\n                    return i;\n            }\n            throw new InvalidOperationException($\"Exceeded maximum number of active LightEpoch instances {ActiveInstanceCount()} {InstanceIndexBuffer.MaxInstances}\");\n        }\n\n        /// <summary>\n        /// Number of active LightEpoch instances. Used for testing and diagnostics.\n        /// </summary>\n        /// <returns></returns>\n        public static int ActiveInstanceCount()\n        {\n            int count = 0;\n            for (var i = 0; i < InstanceIndexBuffer.MaxInstances; i++)\n            {\n                if (kInvalidIndex != InstanceTracker.GetRef(i))\n                    count++;\n            }\n            return count;\n        }\n\n        /// <summary>","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/client/LightEpoch.cs#L179-L215","documentation":"LightEpoch uses a static InstanceTracker of fixed size (MaxInstances = 1024) to assign each LightEpoch instance a unique slot. SelectInstance scans all 1024 slots for one marked kInvalidIndex and claims it; if none is free it throws InvalidOperationException. This caps the total number of simultaneously-live LightEpoch instances process-wide.","triggerScenarios":"Constructing more than 1024 LightEpoch instances in a single process without disposing prior ones; a test harness that creates an epoch per iteration without calling ResetAllInstances() or Dispose().","commonSituations":"Unit tests spinning up many Garnet stores/epochs in a loop; a long-running process leaking LightEpoch instances by forgetting Dispose; integration tests that do not reset static state between runs.","solutions":["Dispose every LightEpoch instance when done so its slot is released back to the static tracker.","In tests, call LightEpoch.ResetAllInstances() between test cases to reclaim leaked slots.","Audit for LightEpoch leaks — the count should stabilize, not grow, over the process lifetime."],"exampleFix":"// before — epoch leaked each iteration\nforeach (var cfg in configs)\n{\n    var epoch = new LightEpoch();\n    epoch.Initialize(...);\n    // ... never disposed ...\n}\n\n// after — dispose to free the instance slot\nforeach (var cfg in configs)\nusing (var epoch = new LightEpoch())\n{\n    epoch.Initialize(...);\n    // ...\n}","handlingStrategy":"validation","validationCode":"// Ensure you are not exceeding the process-wide instance cap before creating more\nif (LightEpoch.ActiveInstanceCount() >= 1024)\n    throw new InvalidOperationException(\"too many live LightEpoch instances; dispose some first\");","typeGuard":"// Use ActiveInstanceCount() to check headroom before constructing a new epoch\nif (LightEpoch.ActiveInstanceCount() < 1024) { /* safe to create */ }","tryCatchPattern":"try { var epoch = new LightEpoch(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"maximum number of active LightEpoch\")) { /* dispose leaked instances and retry */ }","preventionTips":["Dispose every LightEpoch when done to release its instance slot.","Call LightEpoch.ResetAllInstances() between test runs to reclaim leaked slots.","Monitor ActiveInstanceCount() for monotonic growth indicating a leak."],"tags":["csharp","epoch","resource-limit","concurrency","light-epoch"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}