nautechsystems/nautilus_trader · error
Invalid interval_ns: {interval_ns} (must be non-zero)
Error message
Invalid interval_ns: {interval_ns} (must be non-zero) What it means
RateLimit::new_checked validates its inputs before constructing a throttler. This error means interval_ns was 0, which would make the rate-limit window meaningless (division-by-zero / zero-window). The library refuses to construct a RateLimit with a non-zero limit but zero interval.
Source
Thrown at crates/common/src/throttler.rs:70
/// throttling entirely.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct RateLimit {
limit: NonZeroUsize,
interval_ns: NonZeroU64,
}
impl RateLimit {
/// Creates a new [`RateLimit`] instance with correctness checking.
///
/// # Errors
///
/// Returns an error if `limit` or `interval_ns` is zero.
pub fn new_checked(limit: usize, interval_ns: DurationNanos) -> anyhow::Result<Self> {
let limit = NonZeroUsize::new(limit)
.ok_or_else(|| anyhow::anyhow!("Invalid limit: {limit} (must be non-zero)"))?;
let interval_ns = NonZeroU64::new(interval_ns.as_u64()).ok_or_else(|| {
anyhow::anyhow!("Invalid interval_ns: {interval_ns} (must be non-zero)")
})?;
Ok(Self { limit, interval_ns })
}
/// Creates a new [`RateLimit`] instance.
///
/// # Panics
///
/// Panics if `limit` or `interval_ns` is zero.
#[must_use]
pub fn new(limit: usize, interval_ns: DurationNanos) -> Self {
Self::new_checked(limit, interval_ns).expect(FAILED)
}
/// Maximum number of messages that can be sent within the interval.
#[must_use]
pub const fn limit(&self) -> usize {
self.limit.get()View on GitHub (pinned to 18893faf8b)
Solutions
- Pass a positive interval_ns (e.g. DurationNanos for 1s = 1_000_000_000) to new_checked.
- Validate/parse the interval from config before construction and reject 0 early with a clear config error.
- If the interval is derived, check the derivation (e.g. 1_000_000_000 / rate) cannot produce 0 (rate of 0 or clamped).
Example fix
// before let rl = RateLimit::new_checked(100, DurationNanos::default())?; // after let interval_ns = DurationNanos::from(1_000_000_000); // 1 second let rl = RateLimit::new_checked(100, interval_ns)?;
Defensive patterns
Strategy: validation
Validate before calling
let interval_ns_u64 = interval_ns.as_u64();
if limit == 0 || interval_ns_u64 == 0 {
return Err(format!("limit and interval_ns must be non-zero, got limit={limit}, interval_ns={interval_ns_u64}"));
} Try / catch
match RateLimit::new_checked(limit, interval_ns) {
Ok(rl) => rl,
Err(e) => { log::error!("rate limit config invalid: {e}"); return Err(e); }
} Prevention
- Never use DurationNanos::default() (zero) as a real interval.
- Validate interval fields at config load time, before construction.
- Add unit tests covering zero interval config values.
When it happens
Trigger: Calling RateLimit::new_checked(limit, DurationNanos::from(0)) or otherwise passing a zero nanosecond interval while limit is non-zero.
Common situations: Config files where an interval field defaults to 0 or is parsed as an empty/placeholder value; computing interval_ns from a frequency or divisor that evaluates to zero; a config migration that dropped the interval value.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Verified action requires the configured provider identities
- snapshot interval must be positive
- Connection rate keys require a connection rate limiter
- Connection rate limiter requires at least one connection rat
- Unsupported blockchain {blockchain} for RPC connection
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d341c84cbe0c5732.
Report an issue: GitHub.