{"record":{"id":"af608b80bc4bf967","repo":"nautechsystems/nautilus_trader","slug":"failed-to-subtract-months-step","errorCode":null,"errorMessage":"Failed to subtract months_step","messagePattern":"Failed to subtract months_step","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/data/bar.rs","lineNumber":282,"sourceCode":"                )\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),\n                    )\n                    .expect(\"valid UTC year start\")\n                    + origin_offset\n            };","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/data/bar.rs#L264-L300","documentation":"The final subtraction of months_step to return the aligned bar start fails (subtract_n_months returns Err) and the expect panics. After a successful forward loop this should not normally fail, but an origin offset near the lower boundary of jiff's range can push the subtract below the representable minimum.","triggerScenarios":"get_time_bar_start with a Month bar where the loop result sits exactly one months_step above the minimum representable timestamp — e.g. `now` near the epoch lower bound with a large months_step or large negative origin offset.","commonSituations":"Negative/before-1970 timestamps in backtests or data imports; extremely large origin offset in the bar spec; corrupted timestamp data.","solutions":["Ensure `now` and the resulting bar start stay well within jiff's supported range (roughly year -9999 to 9999).","Reduce time_bars_origin magnitude in the bar type configuration.","Clamp inputs to a safe window (e.g. 1900-2200) before calling.","File an issue with reproducing inputs if normal dates trigger it."],"exampleFix":"// before\nlet start = get_time_bar_start(Timestamp::from_unix_nanos(-9_000_000_000_000_000_000), &bar_type, origin);\n// after\nlet clamped = Timestamp::from_unix_nanos(now_ns.max(0));\nlet start = get_time_bar_start(clamped, &bar_type, origin);","handlingStrategy":"validation","validationCode":"if now.as_unix_nanos() < 0 {\n    return Err(\"pre-epoch timestamps unsupported for month bars\".into());\n}\nlet start = get_time_bar_start(now, &bar_type, origin);","typeGuard":"fn post_epoch(ts: Timestamp) -> bool { ts.as_unix_nanos() >= 0 }","tryCatchPattern":"let start = std::panic::catch_unwind(|| get_time_bar_start(now, &bar_type, origin))\n    .map_err(|_| anyhow::anyhow!(\"month bar start subtraction underflowed\"))?;","preventionTips":["Reject negative/pre-epoch timestamps during data ingestion.","Bound origin offsets in bar type configuration.","Clamp timestamps to a safe window (1900-2200) in backtesting setups."],"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"}