risingwavelabs/risingwave · error · InvalidParamsError
Invalid datetime: seconds: {secs}, nanoseconds: {nsecs}
Error message
Invalid datetime: seconds: {secs}, nanoseconds: {nsecs} What it means
ErrorKind::DateTime is raised by Timestamp::with_secs_nsecs when chrono's DateTime::from_timestamp(secs, nsecs) returns None, i.e. the seconds/nanoseconds pair does not represent a representable UTC datetime (secs out of i64-supported range or nsecs >= 1_000_000_000). It is wrapped in InvalidParamsError and bubbles up through Timestamp deserialization.
Source
Thrown at src/common/src/types/datetime.rs:255
/// ```
impl From<Interval> for Time {
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);View on GitHub (pinned to 6469eb736d)
Solutions
- Validate nsecs < 1_000_000_000 and that secs is within chrono's supported range before constructing.
- Normalize nanosecond overflow by carrying it into secs (secs += nsecs / 1e9; nsecs %= 1e9).
- Verify the protobuf encoder/writer version matches the decoder (V0 micros vs V1 secs+nsecs format).
Example fix
// before let ts = Timestamp::with_secs_nsecs(secs, nsecs)?; // after let ts = Timestamp::with_secs_nsecs(secs + (nsecs / 1_000_000_000) as i64, nsecs % 1_000_000_000)?;
Defensive patterns
Strategy: validation
Validate before calling
fn can_be_timestamp(secs: i64, nsecs: u32) -> bool {
nsecs < 1_000_000_000 && (-8334601228800..=8210266876799).contains(&secs)
} Type guard
fn is_safe_epoch_pair(secs: i64, nsecs: u32) -> Option<(i64, u32)> {
if nsecs >= 1_000_000_000 { None } else { Some((secs, nsecs)) }
} Try / catch
match Timestamp::with_secs_nsecs(secs, nsecs) {
Ok(ts) => ts,
Err(e) => return Err(anyhow!("bad timestamp payload: {e}")),
} Prevention
- Carry nanosecond overflow into seconds before construction.
- Treat protobuf payloads as untrusted; validate before decode-dependent construction.
- Keep encoder/decoder versions in sync (V0 vs V1 timestamp format).
When it happens
Trigger: Calling Timestamp::with_secs_nsecs(secs, nsecs) with an out-of-range secs (near i64::MIN/MAX) or nsecs >= 1e9; Time-stamped protobuf decoding (Timestamp::from_protobuf, V1 format) of a corrupted payload.
Common situations: Corrupted or hand-crafted protobuf messages; external systems emitting epoch values far outside the supported range; off-by-one nanosecond arithmetic bugs producing nsecs == 1_000_000_000.
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
- Invalid datetime: {value} {unit} is out of range
- query_epoch not set in distributed lookup join
- Failed to decode prost: field not found `{}`
- Invalid time: {value} {unit} is out of range for a time of d
- Can't cast string to timestamp (expected format is YYYY-MM-D
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/c96ee8d71a229d83.
Report an issue: GitHub.