jdx/mise · error

elapsed timestamp delta must fit into u64

Error message

elapsed timestamp delta must fit into u64

What it means

mise panics with 'elapsed timestamp delta must fit into u64' in `elapsed_seconds_ceil` when the difference between two timestamps, rounded up to whole seconds, exceeds `u64::MAX` — i.e. roughly 584 billion years. The function computes nanosecond deltas between a reference `from` and `to` timestamp (used for `minimum_release_age` checks); since both come from a consistent process clock, this should be impossible and the expect marks it as an invariant.

Source

Thrown at src/duration.rs:21

use eyre::{Result, bail};
use jiff::{Span, Timestamp, Zoned, civil::date};

pub(crate) const HOURLY: Duration = Duration::from_secs(60 * 60);
pub(crate) const DAILY: Duration = Duration::from_secs(60 * 60 * 24);
pub(crate) const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7);

/// Returns the number of whole seconds from `from` to `to`, rounded up.
///
/// Returns 0 when `from >= to` so callers don't have to guard against the
/// degenerate "cutoff is already in the future" case.
pub(crate) fn elapsed_seconds_ceil(from: Timestamp, to: Timestamp) -> u64 {
    if from >= to {
        return 0;
    }
    let nanos = to.as_nanosecond() - from.as_nanosecond();
    u64::try_from((nanos + 999_999_999) / 1_000_000_000)
        .expect("elapsed timestamp delta must fit into u64")
}

/// Returns a stable "now" timestamp for the lifetime of the process.
///
/// This is used for resolving relative durations (e.g. `minimum_release_age = "3d"`)
/// consistently: every resolution of the same relative duration within a single
/// mise invocation produces the same absolute timestamp, and downstream code
/// that converts the absolute timestamp back to a duration (e.g. for npm's
/// `--min-release-age`) gets the exact duration the user specified rather than
/// a slightly-larger value due to wall clock drift between phases.
pub(crate) fn process_now() -> Timestamp {
    static PROCESS_NOW: OnceLock<Timestamp> = OnceLock::new();
    *PROCESS_NOW.get_or_init(Timestamp::now)
}

pub(crate) fn parse_duration(s: &str) -> Result<Duration> {
    match s.parse::<Span>() {
        Ok(span) => {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Verify both timestamps use the same epoch and are produced by `stable_now`/the intended clock
  2. Clamp or validate the resolved release-age timestamp before computing the delta
  3. Return a saturating value (`u64::MAX`) or an error instead of panicking if extreme durations are possible
  4. Check for a typo'd duration unit in `minimum_release_age` config producing an enormous timestamp

Example fix

// before
u64::try_from((nanos + 999_999_999) / 1_000_000_000)
    .expect("elapsed timestamp delta must fit into u64")
// after
u64::try_from((nanos + 999_999_999) / 1_000_000_000)
    .unwrap_or(u64::MAX) // saturate instead of panicking
Defensive patterns

Strategy: validation

Validate before calling

if to.as_nanosecond() - from.as_nanosecond() > u64::MAX as i128 { return Err(...); }

Type guard

fn fits_u64(n: i128) -> bool { (0..=u64::MAX as i128).contains(&n) }

Prevention

When it happens

Trigger: Calling `elapsed_seconds_ceil` with timestamps from inconsistent epochs or corrupted nanosecond values — e.g. a `Timestamp::as_nanosecond` implementation backed by a clock that can go negative or saturate, or callers like `build_transitive_release_age_args`/`aube_project_config` constructing `to` far in the future from a malformed duration.

Common situations: A misconfigured or absurd `minimum_release_age` duration (e.g. a huge relative value) resolved into a far-future timestamp; clock changes or fake/test clocks with negative or extreme values; a change of the timestamp representation widening/narrowing types.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/09f99b838b11a780. Report an issue: GitHub.