libnyanpasu/clash-nyanpasu · warning

version overflow

Error message

version overflow

What it means

StateVersion::next increments a monotonic version counter used for compare-and-swap of state changes. It uses checked_add and panics on overflow because wrapping would break monotonicity and let distinct changes compare as the same version. The panic requires ~u64::MAX increments, so it is a deliberate invariant guard rather than a realistic runtime failure.

Source

Thrown at backend/nyanpasu-core/src/state/version.rs:38

impl AsRef<u64> for Version {
    fn as_ref(&self) -> &u64 {
        &self.0
    }
}

impl Version {
    pub fn new(version: u64) -> Self {
        Self(version)
    }

    /// Return the next monotonic version.
    ///
    /// Panics if the counter overflows, because wrapping would break CAS
    /// monotonicity and may make different state changes compare as the same
    /// version.
    pub fn next(&self) -> Self {
        Self(self.0.checked_add(1).expect("version overflow"))
    }
}

/// Unique identifier for a state change, used for tracking and acknowledgment purposes.
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct StateChangeId(pub Version);

impl Deref for StateChangeId {
    type Target = u64;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl AsRef<u64> for StateChangeId {
    fn as_ref(&self) -> &u64 {

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Nothing to fix in normal use; if hit, restart the process to reset the counter.
  2. In tests, avoid seeding StateVersion with values near u64::MAX unless explicitly testing overflow.
  3. If long-running processes concern you, propose a design change (e.g.128-bit counter) upstream rather than catching the panic.
  4. Treat any occurrence as a bug report: it signals an unbounded state-change loop.

Example fix

// test-only reproduction to avoid
let v = StateVersion(u64::MAX);
let _ = v.next(); // panics: version overflow

// after: use realistic seeded values
let v = StateVersion(0);
let _ = v.next();
Defensive patterns

Strategy: validation

Validate before calling

fn is_safe_to_increment(v: StateVersion) -> bool { v.0 < u64::MAX }

Prevention

When it happens

Trigger: Calling next() when the internal counter is at u64::MAX — i.e. after an astronomically large number of state changes within one process lifetime.

Common situations: Essentially never in production; could only be forced in a test by constructing a version at u64::MAX and calling next().

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 libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/99aad90f72021b95. Report an issue: GitHub.