{"record":{"id":"e7f95c5a7bca3b50","repo":"QuantConnect/Lean","slug":"unexpected-delisting-event-delisting","errorCode":null,"errorMessage":"Unexpected delisting event: {delisting}","messagePattern":"Unexpected delisting event: (.+?)","errorType":"exception","errorClass":"RegressionTestException","httpStatus":null,"severity":"error","filePath":"Algorithm.CSharp/DuplicateOptionAssignmentRegressionAlgorithm.cs","lineNumber":146,"sourceCode":"            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\n                _optionDelisted = true;\n            }\n        }\n\n        public override void OnEndOfAlgorithm()\n        {\n            if (!_optionSold)\n            {\n                throw new RegressionTestException(\"Option was not sold\");\n            }\n\n            if (!_optionAssigned)\n            {\n                throw new RegressionTestException(\"Option was not assigned\");\n            }\n","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.CSharp/DuplicateOptionAssignmentRegressionAlgorithm.cs#L128-L164","documentation":"This is the DelistingType.Delisted (final) phase guard for _option. It requires every prior lifecycle step complete (_optionSold, _optionAssigned, _stockAssigned, _optionDelistedWarningReceived) and the option not already delisted (!_optionDelisted). The final delisting must come exactly once, after the warning. A failure means the final delisting event arrived without its preceding warning or arrived a second time.","triggerScenarios":"Delisted event arrives without a prior Warning (warning skipped), or Delisted arrives twice. Engine change that drops/merges the warning step, or duplicate delisting emission.","commonSituations":"Refactoring the delisting provider so Warning and Delisted collapse into one event; mapping change that changes delisting dates; remapping logic that re-emits delisting.","solutions":["Verify _optionDelistedWarningReceived is true when Delisted fires; if false, the warning was never emitted.","Check Lean's DelistingType handling (Warning vs Delisted) in the Security.Service provider for duplicate emission.","Ensure the final delisting is idempotent or update the test if one-step delisting is the new design."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!_optionDelistedWarningReceived || _optionDelisted)\n{\n    throw new RegressionTestException(\n        $\"Final delisting out of order (warning={_optionDelistedWarningReceived}, delisted={_optionDelisted})\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat delisting as a two-phase state machine and assert transitions explicitly.","Make the final-delisting step idempotent in the engine so it cannot fire twice.","Include prior-phase flags in the final-delisting assertion message."],"tags":["quantconnect","lean","regression-test","options","delisting","ordering","idempotency"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}