nautechsystems/nautilus_trader · error

reservation index overflow

Error message

reservation index overflow

What it means

When a reservation would exceed the sliding-window limit, the code computes how many oldest timestamps must expire (needed) and indexes timestamps[needed - 1] to find when the request can proceed. Because used + weight > limit was checked with saturation and weight <= limit, needed >= 1 and fits in usize, so the expect should be unreachable. A panic indicates the arithmetic invariant was violated (e.g. u32 saturation aliasing with an enormous timestamp count).

Source

Thrown at crates/adapters/bybit/src/common/rate_limit.rs:170

                    if let Some(blocked_until) = window.blocked_until {
                        wait = wait.max(blocked_until.duration_since(now));
                    }

                    let limit = window.limit();
                    if reservation.weight > limit {
                        return Err(format!(
                            "Bybit request weight {} exceeds quota {} for {}",
                            reservation.weight,
                            limit,
                            reservation.key.label(),
                        ));
                    }
                    let used = u32::try_from(window.timestamps.len()).unwrap_or(u32::MAX);
                    if used.saturating_add(reservation.weight) > limit {
                        let needed = used.saturating_add(reservation.weight) - limit;
                        let index =
                            usize::try_from(needed - 1).expect("reservation index overflow");
                        let ready_at = window.timestamps[index] + window.period;
                        wait = wait.max(ready_at.duration_since(now));
                    }
                }

                if wait.is_zero() {
                    for reservation in reservations {
                        let window = windows
                            .get_mut(reservation.key)
                            .expect("Bybit rate-limit window missing after planning");
                        window
                            .timestamps
                            .extend(std::iter::repeat_n(now, reservation.weight as usize));
                    }
                }

                wait
            };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Do not modify the order of the weight <= limit and used + weight > limit checks
  2. If you hit this, inspect window limit configuration for absurd values (limit near u32::MAX)
  3. Use checked arithmetic instead of saturating_add when refactoring this function
  4. Report with the configured limit/period values if it occurs in production

Example fix

// before
let used = u32::try_from(window.timestamps.len()).unwrap_or(u32::MAX);
// after
let used = u32::try_from(window.timestamps.len())
    .expect("sliding window cannot hold more than u32::MAX timestamps");
Defensive patterns

Strategy: try-catch

Validate before calling

// check weight before calling the adapter
assert!(request_weight <= configured_limit, "weight exceeds per-window quota");

Try / catch

// acquire returns Result; treat Err as backpressure, do not unwrap internals
match limiter.acquire(&reservations).await {
    Ok(()) => send_request().await?,
    Err(e) => log::warn!("rate limit rejected request: {e}"),
}

Prevention

When it happens

Trigger: Only if window.timestamps grows beyond u32::MAX entries (u32::try_from fails, used becomes u32::MAX) making needed - 1 impossible, or if the weight/limit guard above is changed. Not reachable with realistic Bybit quotas.

Common situations: Effectively only hit by maintainers modifying the acquire() logic, e.g. reordering the weight check or changing types; not by library users.

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/045a21b7bea26ec2. Report an issue: GitHub.