{"record":{"id":"380138f5fce9e87d","repo":"nautechsystems/nautilus_trader","slug":"callback-should-exist","errorCode":null,"errorMessage":"Callback should exist","messagePattern":"Callback should exist","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/live/clock.rs","lineNumber":168,"sourceCode":"    ) -> anyhow::Result<()> {\n        let ts_now = self.get_time_ns();\n        let (name, alert_time_ns) =\n            validate_and_prepare_time_alert(name, alert_time_ns, allow_past, ts_now)?;\n\n        check_predicate_true(\n            callback.is_some() | self.callbacks.has_any_callback(&name),\n            \"No callbacks provided\",\n        )?;\n\n        self.replace_existing_timer_if_needed(&name);\n\n        let callback = if let Some(callback) = callback {\n            self.callbacks.register_callback(name, callback.clone());\n            callback\n        } else {\n            self.callbacks\n                .get_callback(&name)\n                .expect(\"Callback should exist\")\n        };\n\n        // Safe to calculate interval now that we've ensured alert_time_ns >= ts_now\n        let interval_ns = create_valid_interval(alert_time_ns - ts_now);\n        let fire_immediately = alert_time_ns == ts_now;\n        let sender = self.resolve_time_event_sender();\n\n        let mut timer = LiveTimer::new(\n            name,\n            interval_ns,\n            ts_now,\n            Some(alert_time_ns),\n            callback,\n            fire_immediately,\n            sender,\n        );\n\n        timer.start();","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/live/clock.rs#L150-L186","documentation":"This panic comes from `.expect(\"Callback should exist\")` in `LiveClock::set_time_alert_ns` in crates/common/src/live/clock.rs. When no new callback is supplied, the method assumes a callback was previously registered under `name` and tries to fetch it from the callback registry; if the registry has no entry for that name, the invariant is broken and the clock panics.","triggerScenarios":"Calling `live_clock.set_time_alert_ns(name, alert_time_ns, None)` (or the `_` variant) for a `name` that was never registered with a callback — e.g. the alert was set with None before any registration, the callback was removed via `cancel_timer`/registry clearing, or the name is mistyped.","commonSituations":"Re-registering a persistent time alert after the timer expired and was cleaned up (callback registry entry dropped), typos in timer names between calls, or actors re-arming alerts in `on_stop`/`on_start` cycles where the previous callback was cancelled.","solutions":["Always pass a callback (Some(...)) the first time you register a given time-alert name","Ensure the name matches exactly a previously registered callback; verify with `callback_registered(&name)` before passing None","If the timer may have expired and cleaned up its callback, re-register with a fresh callback instead of None","Check that no code path cancels the timer/callback between registration and re-use"],"exampleFix":"// before\nclock.set_time_alert_ns(\"my_alert\", alert_time_ns, None); // panics if callback was cleaned up\n// after\nif !clock.callback_registered(&\"my_alert\".into()) {\n    clock.set_time_alert_ns(\"my_alert\", alert_time_ns, Some(Callback::from(|event| { /* handle */ })));\n} else {\n    clock.set_time_alert_ns(\"my_alert\", alert_time_ns, None);\n}","handlingStrategy":"type-guard","validationCode":"if !clock.callback_registered(&name) {\n    // register with Some(callback) instead of None\n}","typeGuard":"fn can_rearm(clock: &LiveClock, name: &str) -> bool { clock.callback_registered(&name.into()) }","tryCatchPattern":null,"preventionTips":["Pass Some(callback) on first registration of a name","Check callback_registered before re-arming with None","Use constant timer names; avoid cancel_timer for names you will re-arm with None"],"tags":["rust","panic","timer","callback","live-clock"],"backgroundTag":"resource-not-found","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}