{"record":{"id":"224b26199b3f1809","repo":"nautechsystems/nautilus_trader","slug":"invalid-bar-interval","errorCode":null,"errorMessage":"Invalid bar interval","messagePattern":"Invalid bar interval","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/data/bar.rs","lineNumber":203,"sourceCode":"            // Proxy for comparing bar lengths\n            duration_days(step.checked_mul(30).expect(\"`step` overflows i64 days\"))\n        }\n        BarAggregation::Year => {\n            // Proxy for comparing bar lengths\n            duration_days(step.checked_mul(365).expect(\"`step` overflows i64 days\"))\n        }\n        _ => panic!(\"Aggregation not time based\"),\n    }\n}\n\n/// Returns the bar interval as [`DurationNanos`].\n///\n/// # Panics\n///\n/// Panics if the aggregation method of the given `bar_type` is not time based.\n#[must_use]\npub fn get_bar_interval_ns(bar_type: &BarType) -> DurationNanos {\n    DurationNanos::try_from(get_bar_interval(bar_type)).expect(\"Invalid bar interval\")\n}\n\n/// Returns the time bar start as a timezone-aware `Timestamp`.\n///\n/// # Panics\n///\n/// Panics if computing the base civil date or datetime from `now` fails,\n/// if `step` cannot be represented for the calendar arithmetic,\n/// or if the aggregation type is unsupported.\n#[must_use]\npub fn get_time_bar_start(\n    now: Timestamp,\n    bar_type: &BarType,\n    time_bars_origin: Option<SignedDuration>,\n) -> Timestamp {\n    let spec = bar_type.spec();\n    let step = step_to_i64(spec.step);\n    let origin_offset = time_bars_origin.unwrap_or(SignedDuration::ZERO);","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/data/bar.rs#L185-L221","documentation":"`get_bar_interval_ns` (crates/model/src/data/bar.rs:203) converts the `SignedDuration` returned by `get_bar_interval` into a `DurationNanos` with `try_from(...).expect(\"Invalid bar interval\")`. The conversion fails when the interval is negative or its total nanoseconds exceed what DurationNanos (i64 nanoseconds, ~292 years) can hold, causing this panic.","triggerScenarios":"Calling `get_bar_interval_ns` with a time-based `BarType` whose interval converts to a duration that cannot fit into i64 nanoseconds (e.g. enormous Day/Week/Month/Year steps), or otherwise an interval the try_from rejects.","commonSituations":"Aggregating with a very large step so the interval exceeds i64 nanoseconds; the test `test_time_bar_aggregator_accepts_interval_above_i64_nanos` shows larger intervals are tolerated elsewhere but not representable as DurationNanos here.","solutions":["Reduce the bar step/aggregation so the total interval is under ~292 years (i64 nanoseconds).","If you need longer intervals, avoid get_bar_interval_ns and work with the SignedDuration from get_bar_interval directly.","Validate the step at BarType construction so the resulting interval fits i64 nanoseconds."],"exampleFix":"// before\nlet ns = get_bar_interval_ns(&bar_type); // panics for huge steps\n// after\nlet interval = get_bar_interval(&bar_type);\nassert!(interval.is_positive());\nlet ns = DurationNanos::try_from(interval).unwrap_or_else(|_| {\n    // handle oversized interval explicitly\n    ...\n});","handlingStrategy":"validation","validationCode":"// rust\nfn interval_fits_nanos(bar_type: &BarType) -> bool {\n    let d = get_bar_interval(bar_type);\n    d.is_positive() && DurationNanos::try_from(d).is_ok()\n}","typeGuard":null,"tryCatchPattern":"// Prefer explicit handling over the internal expect:\nlet interval = get_bar_interval(&bar_type);\nlet ns = DurationNanos::try_from(interval)\n    .map_err(|_| BarConfigError::IntervalTooLarge)?;","preventionTips":["Keep bar intervals under i64 nanoseconds (~292 years).","Use get_bar_interval (SignedDuration) when you need very long intervals.","Validate steps when building BarTypes from untrusted config."],"tags":["rust","panic","duration","overflow","bar-aggregation"],"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-14T00:17:10.932Z"}