pola-rs/polars · error
FixedOffset::east out of bounds
Error message
FixedOffset::east out of bounds
What it means
parse_offset splits an offset string like '+05:30' on ':', parses hours and minutes as i32, then calls FixedOffset::east_opt(hours*3600 + minutes*60). chrono requires the total to lie within (-86400, 86400) seconds; the parsing steps check well-formedness only, not magnitude, so a clean-looking '+24:00', '+99:00', or '+00:9999' reaches the .expect and panics.
Source
Thrown at crates/polars-arrow/src/temporal_conversions.rs:301
}
static ERR_MSG: &str = "timezone offset must be of the form [-]00:00";
let mut a = offset.split(':');
let first: &str = a
.next()
.ok_or_else(|| polars_err!(InvalidOperation: ERR_MSG))?;
let last = a
.next()
.ok_or_else(|| polars_err!(InvalidOperation: ERR_MSG))?;
let hours: i32 = first
.parse()
.map_err(|_| polars_err!(InvalidOperation: ERR_MSG))?;
let minutes: i32 = last
.parse()
.map_err(|_| polars_err!(InvalidOperation: ERR_MSG))?;
Ok(FixedOffset::east_opt(hours * 60 * 60 + minutes * 60)
.expect("FixedOffset::east out of bounds"))
}
/// Parses `value` to a [`chrono_tz::Tz`] with the Arrow's definition of timestamp with a timezone.
#[cfg(feature = "chrono-tz")]
#[cfg_attr(docsrs, doc(cfg(feature = "chrono-tz")))]
pub fn parse_offset_tz(timezone: &str) -> PolarsResult<chrono_tz::Tz> {
timezone
.parse::<chrono_tz::Tz>()
.map_err(|_| polars_err!(InvalidOperation: "timezone \"{timezone}\" cannot be parsed"))
}
View on GitHub (pinned to df599052da)
Solutions
- Validate before use: hours in -23..=23 and minutes in 0..=59
- Normalize '+24:00' to '+00:00' (UTC) upstream
- Prefer IANA timezone names ('UTC', 'Europe/Amsterdam') via parse_offset_tz, which returns Err instead of panicking
- Check the computed total seconds is within -86399..=86399
Example fix
// before
let tz = parse_offset("+25:00")?; // panics: FixedOffset::east out of bounds
// after
fn parse_offset_checked(s: &str) -> Option<FixedOffset> {
let (h, m): (i32, i32) = s.strip_prefix(['+', '-'])?.split(':')...
// require h in -23..=23, m in 0..=59, then FixedOffset::east_opt(h * 3600 + m * 60)
} Defensive patterns
Strategy: validation
Validate before calling
fn offset_str_valid(tz: &str) -> bool {
let Some((h, m)) = tz.split_once(':') else { return false };
let (h, m): (i32, i32) = match (h.strip_prefix('+').or(h.strip_prefix('-')).unwrap_or(h).parse(),
m.parse()) {
(Ok(h), Ok(m)) => (h, m),
_ => return false,
};
h.abs() < 24 && (0..=59).contains(&m)
} Prevention
- Validate offset components (|hours| < 24, minutes 0..=59) before calling parse_offset
- Normalize '+24:00' to '+00:00' at the schema boundary
- Prefer IANA tz names handled by parse_offset_tz (returns Err, not a panic)
- Never pass unvetted tz metadata from user input straight into offset parsing
When it happens
Trigger: Passing a fixed-offset timezone string (Arrow timestamp tz metadata) with |hours| >= 24 or minutes that parse but push the total to >= 24h - e.g. schema metadata tz='+25:00' from a hand-written or converted schema.
Common situations: Hand-written parquet/arrow schemas with offset tz strings; producers emitting '+24:00' for UTC; typos in ETL config; sanitized/fuzzed metadata.
Related errors
- not implemented
- not implemented
- not implemented
- horizontal_flatten not supported for data type {:?}
- comparing datetimes with different units or timezones is not
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/655fd84955f11326.
Report an issue: GitHub.