pola-rs/polars · error
Invalid time unit '{tu:?}' for Duration.
Error message
Invalid time unit '{tu:?}' for Duration. What it means
The Duration branch of the JSON serializer has converters only for Nanosecond/Microsecond/Millisecond; Duration(TimeUnit::Second) - legal in Arrow - hits the catch-all panic. Second-precision durations typically enter via arrow-rs interop or hand-constructed arrays.
Source
Thrown at crates/polars-json/src/json/write/serialize.rs:612
array.as_any().downcast_ref().unwrap(),
convert,
offset,
take,
)
},
ArrowDataType::Timestamp(time_unit, Some(tz)) => timestamp_tz_serializer(
array.as_any().downcast_ref().unwrap(),
*time_unit,
tz,
offset,
take,
),
ArrowDataType::Duration(tu) => {
let convert = match tu {
TimeUnit::Nanosecond => duration_ns_to_duration,
TimeUnit::Microsecond => duration_us_to_duration,
TimeUnit::Millisecond => duration_ms_to_duration,
tu => panic!("Invalid time unit '{tu:?}' for Duration."),
};
duration_serializer(
array.as_any().downcast_ref().unwrap(),
convert,
offset,
take,
)
},
ArrowDataType::Time64(tu) => {
let convert = match tu {
TimeUnit::Nanosecond => time64ns_to_time,
tu => panic!("Invalid time unit '{tu:?}' for Time."),
};
time_serializer(
array.as_any().downcast_ref().unwrap(),
convert,
offset,
take,View on GitHub (pinned to 9b5d73fd00)
Solutions
- Cast to Duration(Milliseconds) (or us/ns) before write_json
- Or store as Int64 seconds and format units yourself
- Validate the dtype list before exporting JSON
Example fix
// before: column typed Duration(Second)
df.write_json(&mut out)?; // panic: Invalid time unit 'Second' for Duration.
// after
let df = df.with_column(col("d").cast(&DataType::Duration(TimeUnit::Milliseconds)))?;
df.write_json(&mut out)?; Defensive patterns
Strategy: fallback
Validate before calling
fn normalize_duration_units(df: &DataFrame) -> PolarsResult<DataFrame> {
let mut exprs = vec![];
for (name, dt) in df.schema().iter() {
if matches!(dt, DataType::Duration(TimeUnit::Seconds)) {
exprs.push(col(name).cast(&DataType::Duration(TimeUnit::Milliseconds)).alias(name));
}
}
df.lazy().with_columns(exprs).collect()
}
// run before write_json Type guard
fn has_writable_duration_units(df: &DataFrame) -> bool {
df.schema().iter_values().all(|dt| match dt {
DataType::Duration(tu) => !matches!(tu, TimeUnit::Seconds),
_ => true,
})
} Try / catch
catch_unwind around the write to convert the panic into a clean export error; casting Duration(Second) -> Duration(Milliseconds) beforehand is the durable fix.
Prevention
- Convert second-precision durations to ms/us/ns at ingestion
- Check dtypes in a pre-export validation pass
- Cover every duration unit in export fixtures
When it happens
Trigger: write_json on a column typed ArrowDataType::Duration(TimeUnit::Second), e.g. an arrow-rs array built with DurationSecondType or converted from ISO-8601 'PT5S' values.
Common situations: arrow-rs interop; pipelines that normalized durations to seconds for storage.
Related errors
- Invalid time unit '{tu:?}' for Datetime.
- Invalid time unit '{tu:?}' for Time.
- Timezone {tz} is invalid or not supported
- Invalid Offset format (must be [-]00:00) or timezones featur
- Deserialization from JSON not implemented for {adt:?}
AI-assisted analysis of pola-rs/polars@9b5d73fd00 (2026-08-19).
Data as JSON: /api/errors/d8e100318ca4fcfc.
Report an issue: GitHub.