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
- Nothing to fix in normal use; if hit, restart the process to reset the counter.
- In tests, avoid seeding StateVersion with values near u64::MAX unless explicitly testing overflow.
- If long-running processes concern you, propose a design change (e.g.128-bit counter) upstream rather than catching the panic.
- 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
- Don't seed StateVersion with u64::MAX in tests.
- Restart the process if the counter ever approaches overflow.
- Treat occurrence as a signal of an unbounded change loop.
- Propose a wider counter upstream for ultra-long-lived processes.
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
- semaphore should never closed
- prepare() called more than once with different identifiers.
- URL event received before prepare() was called
- listen() called before prepare()
- prepare() called more than once with different identifiers.
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/99aad90f72021b95.
Report an issue: GitHub.