risingwavelabs/risingwave · error · InvalidParamsError

Invalid datetime: {value} {unit} is out of range

Error message

Invalid datetime: {value} {unit} is out of range

What it means

ErrorKind::Timestamp is raised when a millisecond or microsecond count since the Unix epoch cannot be converted into a Timestamp: DateTime::from_timestamp_millis/micros returns None because the value is out of chrono's representable range. It is produced via InvalidParamsError::timestamp(value, unit) from Timestamp::with_millis / Timestamp::with_micros.

Source

Thrown at src/common/src/types/datetime.rs:257

    fn from(interval: Interval) -> Self {
        let usecs = interval.usecs_of_day();
        let secs = (usecs / 1_000_000) as u32;
        let nano = (usecs % 1_000_000 * 1000) as u32;
        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 {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Clamp or validate the epoch value to chrono's representable range before calling with_millis/with_micros.
  2. Confirm the value's unit (ms vs us vs ns) matches the constructor being used.
  3. Treat sentinel/placeholder values (i64::MIN/MAX, 0 meaning 'unset') explicitly before conversion.

Example fix

// before
let ts = Timestamp::with_micros(raw_i64)?;
// after
let ts = if raw_i64 == i64::MAX { None } else { Some(Timestamp::with_micros(raw_i64)?) };
Defensive patterns

Strategy: validation

Validate before calling

fn can_be_timestamp_millis(ms: i64) -> bool {
    DateTime::from_timestamp_millis(ms).is_some()
}

Type guard

fn is_plausible_epoch_millis(ms: i64) -> bool {
    (-62_167_219_200_000..=253_402_300_799_999).contains(&ms)
}

Try / catch

let ts = Timestamp::with_millis(ms)
    .map_err(|e| anyhow!("epoch ms {ms} out of range: {e}"))?;

Prevention

When it happens

Trigger: Timestamp::with_millis(ms) or Timestamp::with_micros(us) with values beyond ~ +/-262,000 years from 1970 (out of chrono NaiveDateTime range); protobuf deserialization paths that feed a raw i64 into with_micros.

Common situations: Downstream systems sending sentinel values (e.g. i64::MAX) for 'unknown timestamp'; unit confusion where a value in nanoseconds is passed to with_micros; corrupted protobuf frames.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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