risingwavelabs/risingwave · error · IntervalParseError
Invalid unit: {0}
Error message
Invalid unit: {0} What it means
IntervalParseError::InvalidUnit comes from DateTimeField::from_str: the word following a number in an interval literal is not a recognized time unit. Accepted (case-insensitive) units are year(s)/yr(s)/y, day(s)/d, hour(s)/hr(s)/h, minute(s)/min(s)/m, month(s)/mon(s), second(s)/sec(s)/s.
Source
Thrown at src/common/src/types/interval.rs:1024
match ty {
DataType::Interval => self.write(f),
_ => unreachable!(),
}
}
}
/// Error type for parsing an [`Interval`].
#[derive(thiserror::Error, Debug, thiserror_ext::Construct)]
pub enum IntervalParseError {
#[error("Invalid interval: {0}")]
Invalid(String),
#[error(
"Invalid interval: {0}, expected format P<years>Y<months>M<days>DT<hours>H<minutes>M<seconds>S"
)]
InvalidIso8601(String),
#[error("Invalid unit: {0}")]
InvalidUnit(String),
#[error("{0}")]
Uncategorized(String),
}
type ParseResult<T> = std::result::Result<T, IntervalParseError>;
impl Interval {
pub fn as_iso_8601(&self) -> String {
// ISO pattern - PnYnMnDTnHnMnS
let years = self.months / 12;
let months = self.months % 12;
let days = self.days;
let secs_fract = (self.usecs % USECS_PER_SEC).abs();
let total_secs = (self.usecs / USECS_PER_SEC).abs();
let hours = total_secs / 3600;
let minutes = (total_secs / 60) % 60;View on GitHub (pinned to 6469eb736d)
Solutions
- Replace the unit with a supported one: year, month, day, hour, minute, second or their listed abbreviations.
- Convert weeks manually (1 week = 7 days) and microseconds/seconds fractions accordingly.
- Strip trailing punctuation like '.' from generated unit tokens before parsing.
Example fix
// before let iv: Interval = "3 weeks".parse()?; // after let iv: Interval = "21 days".parse()?;
Defensive patterns
Strategy: validation
Validate before calling
const UNITS: &[&str] = &["year","years","yr","yrs","y","day","days","d","hour","hours","hr","hrs","h","minute","minutes","min","mins","m","month","months","mon","mons","second","seconds","sec","secs","s"];
fn is_known_unit(u: &str) -> bool { UNITS.contains(&u.to_lowercase().as_str()) } Type guard
fn is_supported_interval_unit(u: &str) -> bool {
matches!(u.to_lowercase().as_str(), "y" | "yr" | "yrs" | "year" | "years" | "d" | "day" | "days" | "h" | "hr" | "hrs" | "hour" | "hours" | "m" | "min" | "mins" | "minute" | "minutes" | "mon" | "mons" | "month" | "months" | "s" | "sec" | "secs" | "second" | "seconds")
} Try / catch
let unit = DateTimeField::from_str(u)
.map_err(|e| anyhow!("unknown interval unit '{u}': {e}"))?; Prevention
- Map richer unit vocabularies (weeks, ms) to supported units before parsing.
- Strip trailing punctuation from generated unit tokens.
- Keep a central allow-list of unit spellings in code generators.
When it happens
Trigger: Interval literals with misspelled or unsupported units: '3 weeks', '5 fortnights', '2 yrs.' (trailing period), or abbreviations not in the table like 'ms' or 'w'.
Common situations: Migrating from systems with richer unit vocab (weeks, microseconds); typos ('monts'); locale-translated unit names in generated SQL.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid interval: {0}
- Invalid interval: {0}, expected format P<years>Y<months>M<da
- {0}
- Can't cast string to date (expected format is YYYY-MM-DD)
- Can't cast string to time (expected format is HH:MM:SS[.D+{u
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/20fd42828b141a07.
Report an issue: GitHub.