clockworklabs/SpacetimeDB · error
Duration since Unix epoch overflows i64 microseconds
Error message
Duration since Unix epoch overflows i64 microseconds
What it means
Panic in `Timestamp::from_duration_since_unix_epoch`: converting a `std::time::Duration` into a `Timestamp` (i64 microseconds since epoch) requires the microsecond count to fit in `i64` (~±292,471 years around 1970). `try_into().expect("Duration since Unix epoch overflows i64 microseconds")` panics beyond that. Documented as an intentional panic.
Solutions
- Log/inspect the incoming Duration at the call site to identify the arithmetic or unit bug (most common: ns vs ms vs µs confusion).
- Bound computed durations with `checked_mul`/`checked_add` and a sane maximum before building a Timestamp.
- Validate parsed numeric inputs (epoch values, offsets) against a plausible range (e.g. year 1..9999) before conversion.
- Add tests exercising extreme values through timestamp math.
Example fix
// before: unit confusion can overflow
let ts = Timestamp::from_duration_since_unix_epoch(Duration::from_nanos(input_ns));
// after: validate range first
let d = Duration::from_nanos(input_ns);
if d > Duration::from_secs(60 * 60 * 24 * 365 * 5000) { return Err(OutOfRange); }
let ts = Timestamp::from_duration_since_unix_epoch(d); Defensive patterns
Strategy: validation
Validate before calling
const MAX_TS: Duration = Duration::from_secs(60 * 60 * 24 * 365 * 200_000);
fn checked_ts(d: Duration) -> Result<Timestamp, Overflow> {
(d <= MAX_TS).then(|| Timestamp::from_duration_since_unix_epoch(d)).ok_or(Overflow)
} Prevention
- Double-check time units (ns vs µs vs ms) at every conversion boundary — unit bugs cause most overflow hits.
- Bound deadline arithmetic with checked_* ops.
- Validate parsed epoch values against a plausible year range before constructing Timestamps.
When it happens
Trigger: Calling `Timestamp::from_duration_since_unix_epoch(d)` with a Duration larger than ~292k years — typically from overflow-prone arithmetic (duration multiplication, summing intervals), `Duration::MAX`, or unvalidated parsed input. Everyday timestamps never hit this; the trigger is a computed/garbage Duration.
Common situations: Scheduling code computing far-future deadlines with `now + huge_offset`; parsing timestamps with wrong units (nanoseconds fed as milliseconds multiplies value by 1000 repeatedly); fuzz inputs; clock-offset calculations against `SystemTime::MAX`-style extremes.
Related errors
- Duration overflows i64 microseconds
- Timestamp with i64 microseconds before Unix epoch overflows…
- Timestamp with i64 microseconds since Unix epoch overflows…
- SystemTime predates the Unix epoch
- timestamp before unix epoch
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/b4eb205d4ebc9f0e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/sats/src/timestamp.rs:78
/// Returns `Err(duration_before_unix_epoch)` if `self` is before `Self::UNIX_EPOCH`.
pub fn to_duration_since_unix_epoch(self) -> Result<Duration, Duration> {
let micros = self.to_micros_since_unix_epoch();
if micros >= 0 {
Ok(Duration::from_micros(micros as u64))
} else {
Err(Duration::from_micros((-micros) as u64))
}
}
/// Return a [`Timestamp`] which is [`Timestamp::UNIX_EPOCH`] plus `duration`.
///
/// Panics if `duration.as_micros` overflows an `i64`
pub fn from_duration_since_unix_epoch(duration: Duration) -> Self {
Self::from_micros_since_unix_epoch(
duration
.as_micros()
.try_into()
.expect("Duration since Unix epoch overflows i64 microseconds"),
)
}
/// Convert `self` into a [`SystemTime`] which refers to approximately the same point in time.
///
/// This conversion may lose precision, as [`SystemTime`]'s prevision varies depending on platform.
/// E.g. Unix targets have microsecond precision, but Windows only 100-microsecond precision.
///
/// This conversion may panic if `self` is out of bounds for [`SystemTime`].
/// We are not aware of any platforms for which [`SystemTime`] offers a smaller range than [`Timestamp`],
/// but such a platform may exist.
pub fn to_system_time(self) -> SystemTime {
match self.to_duration_since_unix_epoch() {
Ok(positive) => SystemTime::UNIX_EPOCH
.checked_add(positive)
.expect("Timestamp with i64 microseconds since Unix epoch overflows SystemTime"),
Err(negative) => SystemTime::UNIX_EPOCH
.checked_sub(negative)View on GitHub (pinned to 6dee26c6ef)