pola-rs/polars · error
Timezone {tz} is invalid or not supported
Error message
Timezone {tz} is invalid or not supported What it means
timestamp_tz_serializer() first tries parse_offset(tz) (fixed +/-HH:MM form) and then, with the timezones feature, parse_offset_tz(tz) (IANA names via chrono-tz). When both fail, the string is neither a valid offset nor a known zone name, and the writer panics before emitting any JSON. The tz comes straight from the column's DataType::Datetime(_, Some(tz)).
Source
Thrown at crates/polars-json/src/json/write/serialize.rs:476
materialize_serializer(f, array.iter(), offset, take)
},
#[cfg(feature = "timezones")]
_ => match parse_offset_tz(tz) {
Ok(parsed_tz) => {
let f = move |x: Option<&i64>, buf: &mut Vec<u8>| {
if let Some(x) = x {
let dt_str = timestamp_to_datetime(*x, time_unit, &parsed_tz).to_rfc3339();
write!(buf, "\"{dt_str}\"").unwrap();
} else {
buf.extend_from_slice(b"null")
}
};
materialize_serializer(f, array.iter(), offset, take)
},
_ => {
panic!("Timezone {tz} is invalid or not supported");
},
},
#[cfg(not(feature = "timezones"))]
_ => {
panic!("Invalid Offset format (must be [-]00:00) or timezones feature not active");
},
}
}
pub fn new_serializer<'a>(
array: &'a dyn Array,
offset: usize,
take: usize,
) -> Box<dyn JsonSerializer<Item = [u8]> + 'a + Send + Sync> {
match array.dtype().to_storage() {
ArrowDataType::Boolean => {
boolean_serializer(array.as_any().downcast_ref().unwrap(), offset, take)
},View on GitHub (pinned to 9b5d73fd00)
Solutions
- Fix the tz string to a valid IANA name ("America/New_York") or a fixed offset with colon ("+05:30")
- Validate/normalize time zones at ingest and store canonical IANA ids
- If the zone is garbage anyway, drop it before writing: col("ts").dt().replace_time_zone(None)
Example fix
// before
let df = df.with_column(
col("ts").cast(DataType::Datetime(TimeUnit::Microseconds, Some("UTC+2".into()))),
)?.collect()?;
df.write_json(&mut out)?; // panic: Timezone UTC+2 is invalid or not supported
// after
// Some("+02:00".into()) or Some("Europe/Berlin".into()) Defensive patterns
Strategy: validation
Validate before calling
fn tz_writable_by_json(tz: &str) -> bool {
// fixed offset form accepted in all builds
if polars_time::prelude::temporal_conversions::parse_offset(tz).is_ok() { return true; }
// otherwise it must be a known IANA zone (timezones feature)
tz.parse::<chrono_tz::Tz>().is_ok()
}
fn validate_df_tz(df: &DataFrame) -> Result<(), String> {
for (name, dt) in df.schema().iter() {
if let DataType::Datetime(_, Some(tz)) = dt {
if !tz_writable_by_json(tz) { return Err(format!("column {name} has unwritable tz {tz}")); }
}
}
Ok(())
} Type guard
fn has_json_safe_timezones(df: &DataFrame) -> bool {
df.schema().iter_values().all(|dt| match dt {
DataType::Datetime(_, Some(tz)) => tz.parse::<chrono_tz::Tz>().is_ok()
|| polars_time::prelude::temporal_conversions::parse_offset(tz).is_ok(),
_ => true,
})
} Try / catch
catch_unwind(AssertUnwindSafe(|| df.write_json(&mut out))) to fail the export job with the offending column name from your own pre-check; the panic itself only names the tz string.
Prevention
- Normalize tz strings to canonical IANA ids at ingest (validate with chrono_tz::Tz::from_str)
- Reject non-IANA zone ids from user input early
- Drop zones you do not need: replace_time_zone(None) before export
When it happens
Trigger: write_json / JsonWriter on a Datetime column whose tz string is malformed or unknown: "UTC+2" (wrong form), "+0200" (missing colon), "america/new_york" (wrong case), "America/Nowhere" (unknown zone).
Common situations: tz strings captured from user input, HTTP headers, or dirty upstream columns; data round-tripped from systems that write non-IANA zone ids.
Related errors
- Invalid Offset format (must be [-]00:00) or timezones featur
- activate 'timezones' feature
- Invalid time unit '{tu:?}' for Datetime.
- Invalid time unit '{tu:?}' for Duration.
- Invalid time unit '{tu:?}' for Time.
AI-assisted analysis of pola-rs/polars@9b5d73fd00 (2026-08-19).
Data as JSON: /api/errors/261d6ab4933f7c40.
Report an issue: GitHub.