pola-rs/polars · error
Invalid time unit '{tu:?}' for Time.
Error message
Invalid time unit '{tu:?}' for Time. What it means
For Time64 columns the JSON writer only implements the Nanosecond converter; Time64(TimeUnit::Microsecond) - Arrow's other legal 64-bit time-of-day unit - hits the catch-all panic. Time32 columns go through a different branch, so this is specifically 64-bit micro-precision time data.
Source
Thrown at crates/polars-json/src/json/write/serialize.rs:624
),
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,
)
},
ArrowDataType::Null => null_serializer(array.len(), offset, take),
other => todo!("Writing {:?} to JSON", other),
}
}
fn serialize_item<'a>(
buffer: &mut Vec<u8>,
record: impl Iterator<Item = (&'a str, &'a [u8])>,
is_first_row: bool,
) {View on GitHub (pinned to 9b5d73fd00)
Solutions
- Cast to Time64(Nanosecond) (or polars' DataType::Time, stored as ns i64) before write_json
- Or store as Int64 microseconds / a formatted string
- Inspect dtypes before exporting JSON
Example fix
// before: column typed Time64(Microsecond)
df.write_json(&mut out)?; // panic: Invalid time unit 'Microsecond' for Time.
// after
let df = df.with_column(col("t").cast(&DataType::Time))?; // polars Time = ns i64
df.write_json(&mut out)?; Defensive patterns
Strategy: fallback
Validate before calling
fn normalize_time64(df: &DataFrame) -> PolarsResult<DataFrame> {
let mut exprs = vec![];
for (name, dt) in df.schema().iter() {
if matches!(dt, DataType::Time64(TimeUnit::Microsecond)) {
exprs.push(col(name).cast(&DataType::Time).alias(name)); // polars Time = i64 ns
}
}
df.lazy().with_columns(exprs).collect()
}
// run before write_json Type guard
fn has_writable_time64(df: &DataFrame) -> bool {
df.schema().iter_values().all(|dt| match dt {
DataType::Time64(tu) => matches!(tu, TimeUnit::Nanosecond),
_ => true,
})
} Try / catch
catch_unwind around write_json only converts the panic to an error; casting Time64(Microsecond) to nanosecond Time beforehand avoids the failing match arm.
Prevention
- Convert arrow Time64(us) to Time64(ns)/polars Time at interop boundaries
- Validate dtypes before JSON export in a pre-write pass
- Keep a dtype matrix test for every writer your pipeline uses
When it happens
Trigger: write_json on a column typed ArrowDataType::Time64(TimeUnit::Microsecond), e.g. arrays built with arrow-rs' Time64MicrosecondType from another engine's time-of-day output.
Common situations: arrow-rs interop; time-of-day columns produced by engines that store micros since midnight.
Related errors
- Invalid time unit '{tu:?}' for Datetime.
- Invalid time unit '{tu:?}' for Duration.
- 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/9c798d105b7d4ac2.
Report an issue: GitHub.