{"record":{"id":"2b0e638f10000b38","repo":"nautechsystems/nautilus_trader","slug":"durationnanos-overflow-in-from-days","errorCode":null,"errorMessage":"DurationNanos overflow in from_days","messagePattern":"DurationNanos overflow in from_days","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/nanos.rs","lineNumber":218,"sourceCode":"    /// Creates a duration from a number of whole hours.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the result exceeds [`DurationNanos::MAX`].\n    pub const fn try_from_hours(hours: u64) -> Result<Self, DurationNanosOutOfRangeError> {\n        Self::try_from_units(hours, SECONDS_IN_HOUR * NANOSECONDS_IN_SECOND, \"hours\")\n    }\n\n    /// Creates a duration from a number of whole days.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the result exceeds [`DurationNanos::MAX`].\n    #[must_use]\n    pub const fn from_days(days: u64) -> Self {\n        match Self::try_from_days(days) {\n            Ok(duration) => duration,\n            Err(_) => panic!(\"DurationNanos overflow in from_days\"),\n        }\n    }\n\n    /// Creates a duration from a number of whole days.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the result exceeds [`DurationNanos::MAX`].\n    pub const fn try_from_days(days: u64) -> Result<Self, DurationNanosOutOfRangeError> {\n        Self::try_from_units(days, NANOSECONDS_IN_DAY, \"days\")\n    }\n\n    const fn try_from_units(\n        value: u64,\n        nanos_per_unit: u64,\n        unit: &'static str,\n    ) -> Result<Self, DurationNanosOutOfRangeError> {\n        match value.checked_mul(nanos_per_unit) {","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/core/src/nanos.rs#L200-L236","documentation":"`DurationNanos::from_days` converts whole days (u64) to nanoseconds and panics if `days * 86_400 * 1_000_000_000` exceeds `DurationNanos::MAX`. It mirrors the other panicking constructors: the fallible logic lives in `try_from_days`, and overflow is escalated to a panic for this const API.","triggerScenarios":"Calling `DurationNanos::from_days(d)` with `d > u64::MAX / 86_400_000_000_000` (i.e. `d >= 213_503_982` days, about 584 years), causing `try_from_days` to return Err and the panic to fire.","commonSituations":"Sentinel values like u64::MAX days for 'permanent' retention; misconfigured units (hours/months passed as days); property-based tests over full u64 range.","solutions":["Use `DurationNanos::try_from_days(days)` and handle Err.","Validate `days <= u64::MAX / 86_400_000_000_000` before calling.","Clamp to `DurationNanos::MAX` when 'maximum representable' is the intent.","Correct the upstream unit (e.g. value is already in hours)."],"exampleFix":"// before\nlet dur = DurationNanos::from_days(retention_days);\n\n// after\nlet dur = DurationNanos::try_from_days(retention_days)\n    .unwrap_or(DurationNanos::MAX); // saturate 'permanent' retention","handlingStrategy":"validation","validationCode":"const MAX_FROM_DAYS: u64 = u64::MAX / 86_400_000_000_000;\nfn can_convert_days(d: u64) -> bool { d <= MAX_FROM_DAYS }","typeGuard":"fn fits_duration_days(d: u64) -> Option<DurationNanos> {\n    DurationNanos::try_from_days(d).ok()\n}","tryCatchPattern":null,"preventionTips":["Reject day values above ~213 million during input validation.","Use try_from_days for user/config supplied retention windows.","Replace u64::MAX 'permanent' sentinels with Option or a named constant."],"tags":["rust","panic","integer-overflow","duration"],"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"}