nautechsystems/nautilus_trader · error
Timer '{name}' stop time {} is in the past (current time is
Error message
Timer '{name}' stop time {} is in the past (current time is {ts_now}) What it means
When a stop_time_ns is supplied, set_timer_ns also requires it to be in the future (unless allow_past is set). A stop time already in the past means the timer would be born already expired, so the request is rejected rather than registering a useless timer.
Source
Thrown at crates/common/src/clock.rs:878
if !allow_past && next_event_time < ts_now {
anyhow::bail!(
"Timer '{name}' next event time {} would be in the past (current time is {ts_now})",
next_event_time.to_rfc3339(),
);
}
if let Some(stop_time) = stop_time_ns {
if stop_time <= start_time_ns {
anyhow::bail!(
"Timer '{name}' stop time {} must be after start time {}",
stop_time.to_rfc3339(),
start_time_ns.to_rfc3339(),
);
}
if !allow_past && stop_time <= ts_now {
anyhow::bail!(
"Timer '{name}' stop time {} is in the past (current time is {ts_now})",
stop_time.to_rfc3339(),
);
}
}
Ok((
name,
start_time_ns,
stop_time_ns,
allow_past,
fire_immediately,
))
}
/// A deterministic clock for controlled time advancement.
///
/// The clock stores a manual timestamp, schedules [`TestTimer`] instances, and returns due eventsView on GitHub (pinned to 18893faf8b)
Solutions
- Recompute stop_time_ns relative to the current clock time before registering the timer.
- Skip timer registration entirely if the scheduled stop time has already passed (the timer's work window is over).
- Enable allow_past if immediate expiry / past semantics are acceptable.
- Guard in caller code: if stop_time_ns <= clock.timestamp_ns() { return; } before calling set_timer_ns.
Example fix
// before
clock.set_timer_ns("session_timer", interval_ns, start, Some(saved_stop_ns), None, false, false);
// after
let now = clock.timestamp_ns();
if saved_stop_ns > now {
clock.set_timer_ns("session_timer", interval_ns, start, Some(saved_stop_ns), None, false, false);
} Defensive patterns
Strategy: validation
Validate before calling
fn ensure_future_stop(clock: &dyn Clock, stop_time_ns: Option<u64>) -> anyhow::Result<()> {
if let Some(stop) = stop_time_ns {
anyhow::ensure!(stop > clock.timestamp_ns(), "stop {stop} already in the past");
}
Ok(())
} Try / catch
match clock.set_timer_ns(name, interval_ns, start, stop, None, false, false) {
Err(e) if e.to_string().contains("stop time") && e.to_string().contains("in the past") => {
log::warn!("session window already closed, skipping timer");
}
other => other?,
} Prevention
- Recompute session stop times at every startup instead of persisting them
- Skip timer registration when the stop deadline has passed
- Guard against seconds-vs-nanoseconds mistakes (tiny values look 'past')
- Be explicit about allow_past semantics before relying on past stop times
When it happens
Trigger: Calling set_timer_ns with Some(stop_time_ns) <= clock.timestamp_ns() while allow_past is false.
Common situations: Session end times persisted from a previous run and reused; long-running deployment crossing the configured daily/weekly stop time; clock skew; seconds-vs-nanoseconds conversion mistakes making the value tiny and thus 'past'.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Timer '{name}' alert time {} was in the past (current time i
- Timer '{name}' next event time {} would be in the past (curr
- Timer '{name}' stop time {} must be after start time {}
- Event '{}' should have associated handler
- system clock is before UNIX epoch
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f5d40ba6ca3f768c.
Report an issue: GitHub.