nautechsystems/nautilus_trader · error

window index fits u32

Error message

window index fits u32

What it means

`window_index` converts elapsed-nanos-divided-by-window-size into a u32 window counter and panics via `try_from` if it exceeds u32::MAX. Given `RATE_WINDOW_NANOS` (a large constant), uptime would need to exceed roughly 1,36 years of continuous operation for a single counter to overflow — it is an overflow guard, not an expected path.

Source

Thrown at crates/adapters/derive/src/common/rate_limit.rs:431

            )
            .as_str(),
        ),
        RateBucket::CancelAll => Ustr::from(DERIVE_CANCEL_ALL_RATE_KEY),
        RateBucket::CancelByLabel => Ustr::from(DERIVE_CANCEL_BY_LABEL_RATE_KEY),
    }
}

fn resolve_tps(configured: Option<u32>, default_tps: u32) -> u32 {
    configured.filter(|&v| v > 0).unwrap_or(default_tps)
}

fn window_limit(tps: u32) -> NonZeroU32 {
    NonZeroU32::new(tps.saturating_mul(DERIVE_RATE_BURST_MULTIPLIER))
        .expect("window limit must be non-zero")
}

fn window_index(elapsed_nanos: u64) -> u32 {
    u32::try_from(elapsed_nanos / RATE_WINDOW_NANOS).expect("window index fits u32")
}

/// Packs `(window index, consumed)` into one atomic word; the window index in
/// the high half so the default zero value reads as a stale window.
fn pack(window: u32, consumed: u32) -> u64 {
    (u64::from(window) << 32) | u64::from(consumed)
}

fn unpack(packed: u64) -> (u32, u32) {
    (
        u32::try_from(packed >> 32).expect("window index fits u32"),
        packed as u32,
    )
}

/// Outcome of a one-cell consumption attempt against a fixed `window`.
enum CellOutcome {
    Consumed,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Compute elapsed time from a monotonic process-start instant, not from the wall clock / UNIX epoch.
  2. Restart the process periodically (typical for long-running traders) to reset the counter.
  3. Verify RATE_WINDOW_NANOS is unchanged; shrinking the window raises the overflow risk.

Example fix

// before
let elapsed = SystemTime::now().duration_since(UNIX_EPOCH)?.as_nanos() as u64;
// after
let elapsed = start_instant.elapsed().as_nanos() as u64;
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Elapsed time since limiter start exceeding ~2^32 * RATE_WINDOW_NANOS nanoseconds, or a caller passing a bogus `elapsed_nanos` (e.g. a clock computed from a wrong epoch or monotonic-clock mismatch).

Common situations: A process that never restarts across years, or a bug where elapsed time is computed from wall-clock since UNIX epoch instead of process start (instantly huge values).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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