GitoxideLabs/gitoxide · error
Date lies out of range
Error message
Date lies out of range: {}-{:02} What it means
In gix-date's relative-date parsing, `Fields::normalize()` rebuilds a point in time from year/month/day fields. `civil::Date::new(year, month, 1)` fails when the year or month values themselves are outside jiff's supported civil-date range; the code then raises Error 'Date lies out of range: {year}-{month}' as context over the jiff error.
Solutions
- Validate/clamp the requested period count so the resulting date stays within the supported calendar range (roughly years -9999..=9999)
- Catch the Error and reject the relative date expression with a user-facing message about the supported range
- Parse to an absolute timestamp instead of extreme relative offsets
Example fix
// before
parse("now", "999999 years ago")
// after
let years = count.min(9999);
parse("now", &format!("{years} years ago")) Defensive patterns
Strategy: validation
Validate before calling
fn within_calendar_range(year: i32, month: u8) -> bool {
(-9999..=9999).contains(&year) && (1..=12).contains(&month)
} Try / catch
match relative.parse(...) {
Ok(t) => t,
Err(e) => return Err(format!("relative date out of supported range: {e}")),
} Prevention
- Clamp relative period counts to sane magnitudes
- Reject absurd inputs ('999999 years ago') at the UI layer
- Document the supported date range
When it happens
Trigger: `subtract_pairs` (reached via relative-date `parse`) producing year/month fields outside the supported calendar range — e.g. adding or subtracting huge period counts (like '90000 years ago') that push the computed year/month below jiff's minimum (-9999) or above its maximum year.
Common situations: Parsing user input like '999999 years ago' or extreme relative dates in commit-date filters or `git log --since`-style expressions implemented on gix-date.
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
- Day lies out of range
- Couldn't parse span from
- Failed to subtract from
- 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/6b9b5c58f35713f9.
Report an issue: GitHub.
Appendix: source
Thrown at gix-date/src/parse/relative.rs:170
impl From<Zoned> for Fields {
fn from(zdt: Zoned) -> Self {
Fields {
year: zdt.year(),
month: zdt.month(),
day: zdt.day(),
time: zdt.time(),
timezone: zdt.time_zone().clone(),
}
}
}
impl Fields {
/// 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)View on GitHub (pinned to e73179060b)