nautechsystems/nautilus_trader · error

registered callback lease was not acquired

Error message

registered callback lease was not acquired

What it means

`LiveTimer::start` splits dispatch into direct and registered-callback modes. For a registered callback (identified by token) it must have acquired a `registered_lease` from the callback registry; the code asserts this invariant with `.expect`. Missing lease means the timer was configured for a registered callback but the lease was never created/fetched before firing.

Source

Thrown at crates/common/src/live/timer.rs:354

                        break;
                    }
                    None
                };

                if sender.is_some()
                    && let Some(following_next_time_ns) = following_next_time_ns
                {
                    next_time_atomic
                        .store(following_next_time_ns.as_u64(), atomic::Ordering::SeqCst);
                }

                match (&sender, &worker_dispatch) {
                    (Some(sender), WorkerDispatch::Direct(factory)) => {
                        sender.send(factory.message(event));
                    }
                    (Some(sender), WorkerDispatch::Registered(token)) => {
                        let lease =
                            registered_lease.expect("registered callback lease was not acquired");

                        if expires_after_fire {
                            token.close();
                        }
                        sender.send(TimeEventMessage::registered(event, lease));
                    }
                    #[cfg(feature = "python")]
                    (None, WorkerDispatch::SenderlessPython(callback)) => callback.call(event),
                    _ => unreachable!("timer callback dispatch did not match its sender"),
                }

                if sender.is_none()
                    && let Some(following_next_time_ns) = following_next_time_ns
                {
                    next_time_atomic
                        .store(following_next_time_ns.as_u64(), atomic::Ordering::SeqCst);
                }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the registered callback is registered (lease acquired) before `set_timer_ns`/`set_time_alert_ns` fires
  2. Use a direct (closure) callback instead of a registered token if you do not need named registration
  3. Do not close/cancel the registration before the timer fires; close after fire as the code does via `token.close()`
  4. Update/restart the timer after any registry change so a fresh lease is acquired

Example fix

// before
let token = registry.register(name, None); // no lease returned/held
timer.start(event);
// after
let (token, lease) = registry.register(name, callback);
timer.start(event); // registered_lease = Some(lease)
Defensive patterns

Strategy: type-guard

Validate before calling

if timer_is_registered_callback() && registered_lease.is_none() {
    panic-avoid: re-acquire lease or fall back to direct callback before start();
}

Type guard

fn ready_to_start(sender: &Option<Sender>, lease: &Option<Lease>, dispatch: &WorkerDispatch) -> bool {
    !matches!(dispatch, WorkerDispatch::Registered(_)) || lease.is_some()
}

Prevention

When it happens

Trigger: Starting a live timer whose callback is a registered token while `registered_lease` is None — e.g. a senderless/registered-callback configuration path that skipped lease acquisition, or an internal race where the registry entry was removed before start.

Common situations: Custom timer setup mixing direct and registered callback APIs; global-runtime dispatch where lease acquisition is skipped; tests exercising registered callbacks after terminal events closed the registration.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/ae9fd6f5853b75f1. Report an issue: GitHub.