{"record":{"id":"76100a054996071a","repo":"nautechsystems/nautilus_trader","slug":"failed-to-add-months-in-loop","errorCode":null,"errorMessage":"Failed to add months in loop","messagePattern":"Failed to add months in loop","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/data/bar.rs","lineNumber":278,"sourceCode":"                .to_timestamp(\n                    Date::new(now_civil.year(), 1, 1)\n                        .expect(\"valid year start date\")\n                        .at(0, 0, 0, 0),\n                )\n                .expect(\"valid UTC year start\");\n            start_time += origin_offset;\n\n            if now < start_time {\n                start_time =\n                    subtract_n_months(start_time, 12).expect(\"Failed to subtract 12 months\");\n            }\n\n            let months_step =\n                u32::try_from(step).expect(\"`step` exceeds u32 range for month arithmetic\");\n\n            while start_time <= now {\n                start_time =\n                    add_n_months(start_time, months_step).expect(\"Failed to add months in loop\");\n            }\n\n            start_time =\n                subtract_n_months(start_time, months_step).expect(\"Failed to subtract months_step\");\n            start_time\n        }\n        BarAggregation::Year => {\n            let step_i32 =\n                i32::try_from(step).expect(\"`step` exceeds i32 range for year arithmetic\");\n\n            // Reconstruct from Jan 1 + origin each time to avoid leap-day drift\n            let year_start = |year: i32| {\n                let year = i16::try_from(year).expect(\"year exceeds Jiff supported range\");\n                Offset::UTC\n                    .to_timestamp(\n                        Date::new(year, 1, 1)\n                            .expect(\"valid year start date\")\n                            .at(0, 0, 0, 0),","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/data/bar.rs#L260-L296","documentation":"After stepping the Month anchor forward by months_step until it passes `now`, the function subtracts months_step once to land on the last aligned start. If add_n_months returns Err during the loop (timestamp pushed beyond jiff's supported range), the expect panics. This is effectively a timestamp-range overflow, not a normal business condition.","triggerScenarios":"get_time_bar_start with a Month bar where repeatedly adding months_step from the year anchor exceeds the maximum representable jiff timestamp — only reachable with an extreme `now`, huge months_step, or out-of-range origin offset.","commonSituations":"A `now` timestamp far in the future (bad clock, fake/synthetic time misconfigured); a very large month step near u32 bounds combined with an in-range `now`.","solutions":["Sanity-check the `now` Timestamp; it should be a realistic current time.","Reduce the Month step to a sane value (e.g. < 1200 months) before constructing the BarType.","If synthetic/backtesting time is used, keep it within jiff's supported year range.","Report an issue if it reproduces with normal inputs."],"exampleFix":"// before\nget_time_bar_start(now_ns_far_future, &month_bar_type, None)\n// after\nassert!(now.as_unix_nanos() > 0 && now.as_unix_nanos() < 4_102_444_800_000_000_000); // year 2100\nget_time_bar_start(now, &month_bar_type, None)","handlingStrategy":"validation","validationCode":"if now.as_unix_nanos() <= 0 || now.as_unix_nanos() >= 4_102_444_800_000_000_000 {\n    return Err(\"timestamp outside sane range (1970-2100)\".into());\n}\nlet start = get_time_bar_start(now, &bar_type, origin);","typeGuard":"fn sane_timestamp(ts: Timestamp) -> bool {\n    ts.as_unix_nanos() > 0 && ts.as_unix_nanos() < 4_102_444_800_000_000_000\n}","tryCatchPattern":"let start = std::panic::catch_unwind(|| get_time_bar_start(now, &bar_type, origin))\n    .map_err(|_| anyhow::anyhow!(\"month bar start computation overflowed\"))?;","preventionTips":["Sanity-check `now` (real clock or controlled backtest clock) before computing bar starts.","Keep synthetic/backtest time within a bounded window.","Cap month steps to practical magnitudes (< 1200)."],"tags":["rust","panic","calendar-arithmetic","timestamp"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}