risingwavelabs/risingwave · error · InvalidParamsError
Can't cast string to time (expected format is HH:MM:SS[.D+{u
Error message
Can't cast string to time (expected format is HH:MM:SS[.D+{up to 6 digits}][Z] or HH:MM) What it means
ErrorKind::ParseTime is thrown by Time::from_str when speedate::Time::parse_str rejects the input. Accepted shapes are HH:MM:SS[.fraction up to 6 digits][Z] or HH:MM; anything else (e.g. 12-hour clock with AM/PM, missing colon) fails.
Source
Thrown at src/common/src/types/datetime.rs:261
Time::from_num_seconds_from_midnight_uncheck(secs, nano)
}
}
#[derive(Copy, Clone, Debug, Error)]
enum ErrorKind {
#[error("Invalid date: days: {days}")]
Date { days: i32 },
#[error("Invalid time: secs: {secs}, nanoseconds: {nsecs}")]
Time { secs: u32, nsecs: u32 },
#[error("Invalid time: {value} {unit} is out of range for a time of day")]
TimeOfDay { value: u64, unit: &'static str },
#[error("Invalid datetime: seconds: {secs}, nanoseconds: {nsecs}")]
DateTime { secs: i64, nsecs: u32 },
#[error("Invalid datetime: {value} {unit} is out of range")]
Timestamp { value: i64, unit: &'static str },
#[error("Can't cast string to date (expected format is YYYY-MM-DD)")]
ParseDate,
#[error(
"Can't cast string to time (expected format is HH:MM:SS[.D+{{up to 6 digits}}][Z] or HH:MM)"
)]
ParseTime,
#[error(
"Can't cast string to timestamp (expected format is YYYY-MM-DD HH:MM:SS[.D+{{up to 9 digits}}] or YYYY-MM-DD HH:MM or YYYY-MM-DD or ISO 8601 format)"
)]
ParseTimestamp,
}
#[derive(Debug, Error)]
#[error(transparent)]
pub struct InvalidParamsError(#[from] ErrorKind);
impl InvalidParamsError {
pub fn date(days: i32) -> Self {
ErrorKind::Date { days }.into()
}
View on GitHub (pinned to 6469eb736d)
Solutions
- Normalize the input to 24-hour HH:MM:SS(.ffffff) format before casting.
- Strip timezone suffixes other than 'Z' and convert to the desired clock time beforehand.
- Increase fraction precision at the source if more than 6 fractional digits are being sent (only 6 are supported).
Example fix
// before
let t = Time::from_str("04:05:06 PM")?;
// after
let t = Time::from_str("16:05:06")?; Defensive patterns
Strategy: validation
Validate before calling
fn is_parseable_time(s: &str) -> bool {
let s = s.trim_end_matches('Z');
regex::Regex::new(r"^\d{2}:\d{2}(:\d{2}(\.\d{1,6})?)?$").unwrap().is_match(s)
} Type guard
fn looks_like_time(s: &str) -> bool {
let parts: Vec<&str> = s.trim_end_matches('Z').split(':').collect();
(2..=3).contains(&parts.len()) && parts.iter().all(|p| !p.is_empty() && p.chars().all(|c| c.is_ascii_digit() || c == '.'))
} Try / catch
let t = Time::from_str(s)
.map_err(|e| anyhow!("'{s}' is not HH:MM:SS[.ffffff][Z] or HH:MM: {e}"))?; Prevention
- Convert 12-hour AM/PM times to 24-hour before casting.
- Strip or convert timezone suffixes; only 'Z' is tolerated.
- Limit fractional digits to 6 (microsecond precision).
When it happens
Trigger: Casting strings like '4:05 PM', '040506', or '25:00' to TIME; a trailing 'Z' is stripped and ignored, but full timezone offsets like '+08:00' are not accepted.
Common situations: Ingesting logs that use 12-hour AM/PM times; timezone-suffixed times from ISO sources; data exports with zero-padded-omitted components.
Related errors
- Can't cast string to date (expected format is YYYY-MM-DD)
- Can't cast string to timestamp (expected format is YYYY-MM-D
- Invalid time: {value} {unit} is out of range for a time of d
- Invalid interval: {0}
- Invalid interval: {0}, expected format P<years>Y<months>M<da
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/cb6c99172a220174.
Report an issue: GitHub.