pola-rs/polars · error
Invalid Offset format (must be [-]00:00) or timezones featur
Error message
Invalid Offset format (must be [-]00:00) or timezones feature not active
What it means
Without the timezones cargo feature, polars-json can only serialize tz-aware timestamps if the zone parses as a fixed offset via parse_offset ("[-]HH:MM"); every other tz string on a Timestamp column reaches the cfg(not(feature = "timezones")) arm and panics with this combined message. It means: tz-aware column + a zone that is not a bare offset + a build without chrono-tz support.
Source
Thrown at crates/polars-json/src/json/write/serialize.rs:481
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)
},
ArrowDataType::Int8 => {
primitive_serializer::<i8>(array.as_any().downcast_ref().unwrap(), offset, take)
},
ArrowDataType::Int16 => {
primitive_serializer::<i16>(array.as_any().downcast_ref().unwrap(), offset, take)View on GitHub (pinned to 9b5d73fd00)
Solutions
- Enable the timezones feature: polars = { version = "...", features = ["timezones"] }
- Or drop the zone before writing: col("ts").dt().replace_time_zone(None)
- Or write Parquet instead, which serializes tz without going through this path
Example fix
# before
polars = { version = "0.4", default-features = false }
# write_json on Datetime(_, Some("Europe/Amsterdam")) -> panic
# after
polars = { version = "0.4", default-features = false, features = ["timezones"] }
# or in code: col("ts").dt().replace_time_zone(None) Defensive patterns
Strategy: fallback
Validate before calling
fn has_tz_aware(df: &DataFrame) -> bool {
df.schema().iter_values().any(|dt| matches!(dt, DataType::Datetime(_, Some(_))))
}
// without the `timezones` feature only fixed offsets (+HH:MM) serialize;
// fallback: strip zones before write_json
// df.apply("ts", |s| s.datetime().map(|ca| ca.replace_time_zone(None).into_series()))?; Try / catch
catch_unwind around write_json merely re-labels the panic; the schema pre-check plus replace_time_zone(None) fallback keeps the export working without the feature.
Prevention
- Smoke-test a tz-aware JSON export in CI to catch missing features at build time
- Keep one canonical polars feature list for all services
- If IANA zones are required in JSON output, make timezones a hard build requirement
When it happens
Trigger: write_json (JsonWriter/JsonLinesWriter) over Datetime(_, Some("Europe/Amsterdam")) in a build where the timezones feature is disabled. Fixed offsets like "+02:00" still work; IANA names do not.
Common situations: Minimal-feature Rust services exporting JSON; data ported from python-polars (where the feature is always present) into a trimmed Rust deployment.
Related errors
- activate 'timezones' feature
- Timezone {tz} is invalid or not supported
- 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/3a3af21d21a2c166.
Report an issue: GitHub.