{"record":{"id":"045a21b7bea26ec2","repo":"nautechsystems/nautilus_trader","slug":"reservation-index-overflow","errorCode":null,"errorMessage":"reservation index overflow","messagePattern":"reservation index overflow","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/common/rate_limit.rs","lineNumber":170,"sourceCode":"\n                    if let Some(blocked_until) = window.blocked_until {\n                        wait = wait.max(blocked_until.duration_since(now));\n                    }\n\n                    let limit = window.limit();\n                    if reservation.weight > limit {\n                        return Err(format!(\n                            \"Bybit request weight {} exceeds quota {} for {}\",\n                            reservation.weight,\n                            limit,\n                            reservation.key.label(),\n                        ));\n                    }\n                    let used = u32::try_from(window.timestamps.len()).unwrap_or(u32::MAX);\n                    if used.saturating_add(reservation.weight) > limit {\n                        let needed = used.saturating_add(reservation.weight) - limit;\n                        let index =\n                            usize::try_from(needed - 1).expect(\"reservation index overflow\");\n                        let ready_at = window.timestamps[index] + window.period;\n                        wait = wait.max(ready_at.duration_since(now));\n                    }\n                }\n\n                if wait.is_zero() {\n                    for reservation in reservations {\n                        let window = windows\n                            .get_mut(reservation.key)\n                            .expect(\"Bybit rate-limit window missing after planning\");\n                        window\n                            .timestamps\n                            .extend(std::iter::repeat_n(now, reservation.weight as usize));\n                    }\n                }\n\n                wait\n            };","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/common/rate_limit.rs#L152-L188","documentation":"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).","triggerScenarios":"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.","commonSituations":"Effectively only hit by maintainers modifying the acquire() logic, e.g. reordering the weight check or changing types; not by library users.","solutions":["Do not modify the order of the weight <= limit and used + weight > limit checks","If you hit this, inspect window limit configuration for absurd values (limit near u32::MAX)","Use checked arithmetic instead of saturating_add when refactoring this function","Report with the configured limit/period values if it occurs in production"],"exampleFix":"// before\nlet used = u32::try_from(window.timestamps.len()).unwrap_or(u32::MAX);\n// after\nlet used = u32::try_from(window.timestamps.len())\n    .expect(\"sliding window cannot hold more than u32::MAX timestamps\");","handlingStrategy":"try-catch","validationCode":"// check weight before calling the adapter\nassert!(request_weight <= configured_limit, \"weight exceeds per-window quota\");","typeGuard":null,"tryCatchPattern":"// acquire returns Result; treat Err as backpressure, do not unwrap internals\nmatch limiter.acquire(&reservations).await {\n    Ok(()) => send_request().await?,\n    Err(e) => log::warn!(\"rate limit rejected request: {e}\"),\n}","preventionTips":["Configure realistic Bybit limits (not near u32::MAX)","Do not modify the check ordering inside acquire() when customizing","Keep request weights within documented venue quotas"],"tags":["panic","invariant","rate-limit","arithmetic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}