{"record":{"id":"655fd84955f11326","repo":"pola-rs/polars","slug":"fixedoffset-east-out-of-bounds","errorCode":null,"errorMessage":"FixedOffset::east out of bounds","messagePattern":"FixedOffset::east out of bounds","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-arrow/src/temporal_conversions.rs","lineNumber":301,"sourceCode":"    }\n    static ERR_MSG: &str = \"timezone offset must be of the form [-]00:00\";\n\n    let mut a = offset.split(':');\n    let first: &str = a\n        .next()\n        .ok_or_else(|| polars_err!(InvalidOperation: ERR_MSG))?;\n    let last = a\n        .next()\n        .ok_or_else(|| polars_err!(InvalidOperation: ERR_MSG))?;\n    let hours: i32 = first\n        .parse()\n        .map_err(|_| polars_err!(InvalidOperation: ERR_MSG))?;\n    let minutes: i32 = last\n        .parse()\n        .map_err(|_| polars_err!(InvalidOperation: ERR_MSG))?;\n\n    Ok(FixedOffset::east_opt(hours * 60 * 60 + minutes * 60)\n        .expect(\"FixedOffset::east out of bounds\"))\n}\n\n/// Parses `value` to a [`chrono_tz::Tz`] with the Arrow's definition of timestamp with a timezone.\n#[cfg(feature = \"chrono-tz\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"chrono-tz\")))]\npub fn parse_offset_tz(timezone: &str) -> PolarsResult<chrono_tz::Tz> {\n    timezone\n        .parse::<chrono_tz::Tz>()\n        .map_err(|_| polars_err!(InvalidOperation: \"timezone \\\"{timezone}\\\" cannot be parsed\"))\n}\n","sourceCodeStart":283,"sourceCodeEnd":312,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/crates/polars-arrow/src/temporal_conversions.rs#L283-L312","documentation":"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.","triggerScenarios":"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.","commonSituations":"Hand-written parquet/arrow schemas with offset tz strings; producers emitting '+24:00' for UTC; typos in ETL config; sanitized/fuzzed metadata.","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"],"exampleFix":"// before\nlet tz = parse_offset(\"+25:00\")?; // panics: FixedOffset::east out of bounds\n\n// after\nfn parse_offset_checked(s: &str) -> Option<FixedOffset> {\n    let (h, m): (i32, i32) = s.strip_prefix(['+', '-'])?.split(':')...\n    // require h in -23..=23, m in 0..=59, then FixedOffset::east_opt(h * 3600 + m * 60)\n}","handlingStrategy":"validation","validationCode":"fn offset_str_valid(tz: &str) -> bool {\n    let Some((h, m)) = tz.split_once(':') else { return false };\n    let (h, m): (i32, i32) = match (h.strip_prefix('+').or(h.strip_prefix('-')).unwrap_or(h).parse(),\n                                    m.parse()) {\n        (Ok(h), Ok(m)) => (h, m),\n        _ => return false,\n    };\n    h.abs() < 24 && (0..=59).contains(&m)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","polars","arrow","timezone","offset","panic"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}