{"record":{"id":"b56f8c38fb39cabc","repo":"influxdata/influxdb","slug":"generation-duration-overflows-u64-nanoseconds","errorCode":null,"errorMessage":"generation duration overflows u64 nanoseconds","messagePattern":"generation duration overflows u64 nanoseconds","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"influxdb3_catalog/src/catalog/migrations/v3.rs","lineNumber":240,"sourceCode":"    snapshot_next: u64,\n    derived_next: u64,\n    batch: &mut RecordBatch,\n) {\n    if snapshot_next > derived_next {\n        batch.push(&SetNextId {\n            scope,\n            id: snapshot_next,\n        });\n    }\n}\n\nimpl FromV2 for GenerationConfigSnapshot {\n    fn from_v2(&self, batch: &mut RecordBatch) {\n        for (level, duration) in &self.generation_durations {\n            batch.push(&SetGenerationDuration {\n                level: *level,\n                duration_ns: u64::try_from(duration.as_nanos())\n                    .expect(\"generation duration overflows u64 nanoseconds\"),\n            });\n        }\n    }\n}\n\nimpl FromV2 for NodeSnapshot {\n    /// `RegisterNode` is always emitted. For nodes whose state is Stopped, v2\n    /// doesn't preserve the original registration timestamp — use 0 as the\n    /// documented placeholder, then emit `StopNode` to drive the node into\n    /// the Stopped state on apply.\n    fn from_v2(&self, batch: &mut RecordBatch) {\n        let registered_time_ns = match &self.state {\n            NodeStateSnapshot::Running { registered_time_ns } => *registered_time_ns,\n            NodeStateSnapshot::Stopped { .. } => 0,\n        };\n\n        batch.push(&RegisterNode {\n            node_catalog_id: self.node_catalog_id.get(),","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_catalog/src/catalog/migrations/v3.rs#L222-L258","documentation":"A `.expect(...)` panic in the v2->v3 migration when converting a v2 generation duration (a `Duration`) to `u64` nanoseconds via `u64::try_from(duration.as_nanos())`. It fires only if a v2 catalog stores a generation duration of 256+ years (`as_nanos()` exceeds `u64::MAX`), which the v3 `SetGenerationDuration` record cannot represent.","triggerScenarios":"Running `check_and_migrate_v2_to_v3` over a v2 catalog whose `generation_durations` map contains a duration whose nanosecond count does not fit in u64 (>= ~584.9 years of nanoseconds... specifically > u64::MAX ns, i.e. >= 2^64 ns).","commonSituations":"Hand-modified or corrupted v2 catalog snapshots with absurd generation durations; test fixtures using `Duration::MAX`; catalogs written by tooling that didn't bound-check duration values.","solutions":["Locate the offending generation duration in the v2 catalog snapshot and correct it to a realistic value (e.g. seconds/hours).","Restore the v2 catalog object from a backup taken before the bad value was written.","If you control the source, replace `expect` with a fallible conversion and emit `MigrationError::Unexpected` instead of panicking.","Report to InfluxData if legitimate v2 data triggers this — it indicates the migration lacks graceful overflow handling."],"exampleFix":"// before\n.expect(\"generation duration overflows u64 nanoseconds\")\n// after\n.duration_ns(u64::try_from(duration.as_nanos()).map_err(|_| {\n    MigrationError::Unexpected(anyhow::anyhow!(\"generation duration {duration:?} overflows u64 ns\"))\n})?)","handlingStrategy":"validation","validationCode":"fn generation_duration_is_representable(d: std::time::Duration) -> bool {\n    u64::try_from(d.as_nanos()).is_ok()\n}","typeGuard":"fn fits_u64_nanos(v: u128) -> bool { v <= u64::MAX as u128 }","tryCatchPattern":"// panic, not recoverable at runtime; pre-validate any duration you write to a v2 catalog\nassert!(fits_u64_nanos(d.as_nanos()), \"generation duration too large for v3 migration\");","preventionTips":["Never write hand-tuned absurd generation durations (use seconds/minutes/hours).","Clamp durations at write time to a sane maximum.","Validate v2 catalog fixtures with fits_u64_nanos before migration testing.","Prefer fallible try_from in code you own instead of expect."],"tags":["influxdb3","catalog-migration","overflow","panic","rust"],"backgroundTag":"value-out-of-range","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}