risingwavelabs/risingwave · error · IntervalParseError
Invalid interval: {0}, expected format P<years>Y<months>M<da
Error message
Invalid interval: {0}, expected format P<years>Y<months>M<days>DT<hours>H<minutes>M<seconds>S What it means
IntervalParseError::InvalidIso8601 is raised when parsing an ISO 8601 duration string fails the strict P<n>Y<n>M<n>DT<n>H<n>M<n>S shape. The parser attempts each component and, if any step fails or overflow checks fail, reports the whole string as invalid ISO 8601.
Source
Thrown at src/common/src/types/interval.rs:1019
fn write<W: std::fmt::Write>(&self, f: &mut W) -> std::fmt::Result {
write!(f, "{self}")
}
fn write_with_type<W: std::fmt::Write>(&self, ty: &DataType, f: &mut W) -> std::fmt::Result {
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;View on GitHub (pinned to 6469eb736d)
Solutions
- Emit a strictly canonical ISO 8601 duration: starts with 'P', ordered Y/M/D then T H/M/S, uppercase.
- Remove empty components (e.g. use 'PT0S' instead of 'PT').
- Reduce the magnitude if component multiplication overflows i64 microseconds.
Example fix
// before
let iv = Interval::parse_iso8601("p1y")?;
// after
let iv = Interval::parse_iso8601("P1Y")?; Defensive patterns
Strategy: validation
Validate before calling
fn is_iso8601_duration(s: &str) -> bool {
regex::Regex::new(r"^P(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+(\.\d+)?S)?)?$").unwrap()
.is_match(s) && s != "P"
} Type guard
fn looks_like_iso_duration(s: &str) -> bool {
s.starts_with('P') && s.len() > 1 && s.chars().all(|c| c.is_ascii_uppercase() || c.is_ascii_digit() || c == '.')
} Try / catch
let iv = Interval::parse_iso8601(s)
.map_err(|e| anyhow!("'{s}' is not a valid ISO 8601 duration: {e}"))?; Prevention
- Always emit uppercase, canonical P..Y..M..DT..H..M..S strings.
- Avoid empty component strings like 'PT'; use 'PT0S'.
- Keep component magnitudes small enough to fit i64 microseconds after conversion.
When it happens
Trigger: Strings like 'P1Y2M' handled fine but 'PT' (empty components), 'P' alone, '1Y2M' (missing leading 'P'), lowercase 'p1y', or values whose products overflow i64 (checked_mul/checked_add fail) in Interval::parse_iso8601.
Common situations: Feeding Java/Python datetime.timedelta-style strings ('1 day, 0:00:00') that only look ISO-like; decimal values in fields where the parser doesn't accept them; extremely large duration values overflowing i64 microseconds.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- Invalid interval: {0}
- Invalid unit: {0}
- {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/c1c650fef064ae4a.
Report an issue: GitHub.