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

  1. Replace the unit with a supported one: year, month, day, hour, minute, second or their listed abbreviations.
  2. Convert weeks manually (1 week = 7 days) and microseconds/seconds fractions accordingly.
  3. 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

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


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/20fd42828b141a07. Report an issue: GitHub.