GitoxideLabs/gitoxide · error
Couldn't parse span from
Error message
Couldn't parse span from '{period} {count}' What it means
In gix-date's relative-date `subtract_pairs`, each (count, unit) pair must be convertible into a jiff `Span`. The closure `err` builds Error 'Couldn't parse span from \'{period} {count}\'' raised when `count.checked_mul(factor)` overflows for `Unit::Seconds(factor)` (and analogous failures building spans for other units), i.e. the numeric count times its factor does not fit.
Solutions
- Reduce the count to a value that fits when multiplied by the unit factor (keep counts within i64-safe bounds)
- Pre-validate the numeric count before handing the pair list to gix-date
- Catch the Error and report the offending 'period count' text to the user
Example fix
// before
parse(now, "18446744073709551615 seconds ago")
// after
let count = count.min(i64::MAX as u64 / factor);
parse(now, &format!("{count} seconds ago")) Defensive patterns
Strategy: validation
Validate before calling
fn count_safe(count: u64, factor: u64) -> bool {
count.checked_mul(factor).is_some()
} Try / catch
match parse_relative(input) {
Ok(t) => t,
Err(e) => { warn!("bad relative date: {e}"); now() },
} Prevention
- Validate numeric magnitude of relative-date components before parsing
- Clamp counts to i64-safe bounds per unit factor
- Reject nonsensical inputs early with clear user messages
When it happens
Trigger: Calling relative-date `parse` (directly or via `gix_date::parse`) with a pair whose count is huge — e.g. '18446744073709551615 seconds ago' — where `checked_mul` on the second-factor overflows i64/u64.
Common situations: Users passing absurdly large numbers to relative date expressions (`--since=999999999999999999999 seconds ago`) in tooling built on gix-date.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- Day lies out of range
- Failed to subtract from
- Date lies out of range
- cannot find character that we didn't search for
- (re-raised revision-spec parse error via bail!(err))
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/28dcb51b57aefc05.
Report an issue: GitHub.
Appendix: source
Thrown at gix-date/src/parse/relative.rs:184
/// Turn the fields back into a point in time: a day beyond the end of the month rolls over into the
/// following month. One month before May 31st is thus May 1st, a day after April 30th.
fn normalize(&self) -> Result<Zoned, Exn<Error>> {
let first_of_month = civil::Date::new(self.year, self.month, 1)
.or_raise(|| Error::new(format!("Date lies out of range: {}-{:02}", self.year, self.month)))?;
let days_beyond_first = SignedDuration::from_secs((i64::from(self.day) - 1) * 24 * 60 * 60);
first_of_month
.checked_add(days_beyond_first)
.or_raise(|| Error::new(format!("Day {} lies out of range", self.day)))?
.to_datetime(self.time)
.to_zoned(self.timezone.clone())
.or_raise(|| Error::new("Could not convert date to a point in time"))
}
}
let now = now.ok_or(ValidationError::new("Missing current time"))?;
let mut fields = Fields::from(now);
for Pair { period, count, unit } in pairs {
let err = || Error::new(format!("Couldn't parse span from '{period} {count}'"));
match unit {
Unit::Seconds(factor) => {
let seconds = count
.checked_mul(*factor)
.map(SignedDuration::from_secs)
.ok_or_else(err)?;
let ts = fields.normalize()?.timestamp().checked_sub(seconds).or_raise(err)?;
fields = ts.to_zoned(fields.timezone.clone()).into();
}
Unit::Months(factor) => {
let months = count.checked_mul(*factor).ok_or_else(err)?;
fields = fields.normalize()?.into();
let total = (i64::from(fields.year) * 12 + i64::from(fields.month) - 1)
.checked_sub(months)
.ok_or_else(err)?;
fields.year = i16::try_from(total.div_euclid(12)).ok().ok_or_else(err)?;
fields.month = i8::try_from(total.rem_euclid(12) + 1).expect("a value in 1..=12");
}View on GitHub (pinned to e73179060b)