{"record":{"id":"b9f96e2b6d7a3f8a","repo":"QuantConnect/Lean","slug":"unexpected-delisting-events","errorCode":null,"errorMessage":"Unexpected delisting events","messagePattern":"Unexpected delisting events","errorType":"exception","errorClass":"RegressionTestException","httpStatus":null,"severity":"error","filePath":"Algorithm.CSharp/DuplicateOptionAssignmentRegressionAlgorithm.cs","lineNumber":130,"sourceCode":"                }\n            }\n            else if (orderEvent.Status == OrderStatus.Canceled)\n            {\n                // The delisted event is received before the order is canceled\n                if (!_optionSold || !_optionAssigned || !_stockAssigned || !_optionDelistedWarningReceived || !_optionDelisted)\n                {\n                    throw new RegressionTestException($\"Unexpected cancel event: {orderEvent}\");\n                }\n\n                _orderCanceled = true;\n            }\n        }\n\n        public override void OnDelistings(Delistings delistings)\n        {\n            if (!delistings.TryGetValue(_option, out var delisting))\n            {\n                throw new RegressionTestException($\"Unexpected delisting events\");\n            }\n\n            if (delisting.Type == DelistingType.Warning)\n            {\n                if (!_optionSold || !_optionAssigned || !_stockAssigned || _optionDelistedWarningReceived)\n                {\n                    throw new RegressionTestException($\"Unexpected delisting warning event: {delisting}\");\n                }\n\n                _optionDelistedWarningReceived = true;\n            }\n            else\n            {\n                if (!_optionSold || !_optionAssigned || !_stockAssigned || !_optionDelistedWarningReceived || _optionDelisted)\n                {\n                    throw new RegressionTestException($\"Unexpected delisting event: {delisting}\");\n                }\n","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.CSharp/DuplicateOptionAssignmentRegressionAlgorithm.cs#L112-L148","documentation":"This assertion sits in OnDelistings of a regression algorithm that sells an option, expects it to be assigned (stock delivered), then expects the option to delist. It enforces that every Delistings collection delivered to the algorithm contains the specific option symbol (_option) the test holds. QuantConnect Lean dispatches a Delistings collection per time step; if delistings.TryGetValue(_option, ...) returns false, the engine sent a delisting for a symbol other than the one the test tracks, which means the delisting pipeline produced an off-target or spurious event.","triggerScenarios":"A delisting event arrives whose Symbol != _option (e.g. the underlying stock delists, a second option contract is delisted, or the collection is empty). Triggered by changes to the delisting dispatcher in AlgorithmManager or the delisting event provider emitting for an unexpected canonical/security.","commonSituations":"Refactoring SecurityService/SubscriptionManager so a duplicate security lingers and delists; introducing a new auxiliary symbol in the test that carries delisting metadata; data-file changes adding delisting info for an extra symbol; an option canonical symbol resolution change.","solutions":["Log every entry in the Delistings collection at the throw site to see which Symbol/Type arrived unexpectedly.","Trace delisting event generation in Lean (Delisting provider / SecurityManager) for the unexpected symbol and find who created that security.","If the extra event is expected after your engine change, widen the assertion to allow it; otherwise fix the engine to stop emitting the spurious delisting."],"exampleFix":"// before\nif (!delistings.TryGetValue(_option, out var delisting))\n{\n    throw new RegressionTestException($\"Unexpected delisting events\");\n}\n\n// after (diagnostic + tolerant of known extra symbol)\nif (!delistings.TryGetValue(_option, out var delisting))\n{\n    throw new RegressionTestException(\n        $\"Unexpected delisting events. Got: {string.Join(\", \", delistings.Select(d => $\"{d.Symbol}:{d.Type}\"))}\");\n}","handlingStrategy":"validation","validationCode":"// Validate the delistings collection before asserting on a single symbol\nif (delistings == null || !delistings.Any())\n{\n    // no delistings this step; nothing to assert\n    return;\n}\nvar unexpected = delistings.Where(d => d.Symbol != _option).ToList();\nif (unexpected.Count > 0)\n{\n    throw new RegressionTestException(\n        $\"Off-target delisting(s): {string.Join(\", \", unexpected.Select(d => $\"{d.Symbol}:{d.Type}\"))}\");\n}","typeGuard":null,"tryCatchPattern":"try { var delisting = delistings[_option]; /* use */ }\ncatch (KeyNotFoundException) { /* log full collection, then rethrow with context */ }","preventionTips":["Always log the full Delistings collection contents, not just the expected symbol.","When adding securities to a regression algorithm, account for every symbol that could delist.","Guard regression handlers against empty collections before indexing."],"tags":["quantconnect","lean","regression-test","options","delisting","event-validation"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}