{"record":{"id":"709e448967857cdb","repo":"influxdata/influxdb","slug":"cannot-fit-duration-into-u64","errorCode":null,"errorMessage":"cannot fit duration into u64","messagePattern":"cannot fit duration into u64","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/metric/src/duration.rs","lineNumber":25,"sourceCode":"\nuse std::convert::TryInto;\n\n/// The maximum duration that can be stored in the duration measurements\npub const DURATION_MAX: Duration = Duration::from_nanos(u64::MAX);\n\n/// A monotonic counter of `std::time::Duration`\n#[derive(Debug, Clone, Default)]\npub struct DurationCounter {\n    inner: U64Counter,\n}\n\nimpl DurationCounter {\n    pub fn inc(&self, duration: Duration) {\n        self.inner.inc(\n            duration\n                .as_nanos()\n                .try_into()\n                .expect(\"cannot fit duration into u64\"),\n        )\n    }\n\n    pub fn fetch(&self) -> Duration {\n        Duration::from_nanos(self.inner.fetch())\n    }\n}\n\nimpl MetricObserver for DurationCounter {\n    type Recorder = Self;\n\n    fn kind() -> MetricKind {\n        MetricKind::DurationCounter\n    }\n\n    fn recorder(&self) -> Self::Recorder {\n        self.clone()\n    }","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/influxdata/influxdb/blob/d28e26e048401c53cbb98cf2d6ab0cf1e98048ca/core/metric/src/duration.rs#L7-L43","documentation":"DurationCounter stores durations as nanosecond counts in a U64Counter. inc() converts the Duration via as_nanos() (u128) and try_into::<u64>(); durations longer than u64::MAX nanoseconds (about 584 years) cannot fit and the expect panics. Real elapsed times never approach this - it fires only on absurd or broken Duration values.","triggerScenarios":"Calling counter.inc(duration) with Duration::MAX, or with a Duration produced by arithmetic bugs such as Duration::from_secs(u64::MAX), saturating accumulation across retry loops, or a duration built from a wrapped/negative i64 nanoseconds cast.","commonSituations":"Retry/storm loops that accumulate elapsed time into one Duration before reporting it once; conversions where a negative i64 nanosecond delta became a huge unsigned value.","solutions":["Find the code producing the Duration - anything over ~584 years means an arithmetic or unit bug upstream","Report per-interval durations instead of accumulating them into a single Duration","Clamp before recording: d = std::cmp::min(d, Duration::from_secs(3600))","At the call site, convert defensively: d.as_nanos().try_into().unwrap_or(u64::MAX) instead of relying on the library's expect"],"exampleFix":"// before\ncounter.inc(total_elapsed);  // accumulated across the whole process -> can be huge\n\n// after\ncounter.inc(interval_elapsed.min(Duration::from_secs(3600)));\n","handlingStrategy":"validation","validationCode":"// bound any duration before it reaches the metric\nfn clamp_duration(d: Duration) -> Duration {\n    d.min(Duration::from_secs(3600))\n}\ncounter.inc(clamp_duration(measured));\n","typeGuard":"fn fits_u64_nanos(d: Duration) -> bool {\n    u64::try_from(d.as_nanos()).is_ok()\n}\n","tryCatchPattern":null,"preventionTips":["Record per-interval durations; never accumulate them into one Duration","Fix unit/sign bugs where negative i64 nanosecond deltas become huge unsigned values","Debug-assert durations against a sane upper bound (e.g. 1 hour) during development"],"tags":["metrics","duration","overflow","panic","influxdb3"],"backgroundTag":"duration-overflow-panic","analyzedSha":"d28e26e048401c53cbb98cf2d6ab0cf1e98048ca","analyzedAt":"2026-08-16T19:53:34.623Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}