cube-js/cube · error
Invalid timestamp: {}
Error message
Invalid timestamp: {} What it means
to_naive_datetime converts a Timestamp's unix_nano field to a chrono NaiveDateTime via DateTime::from_timestamp. If the nanosecond count is outside the representable range (roughly years 1677–2262, the i64-nanosecond limit), from_timestamp returns None and the code panics with 'Invalid timestamp: <n>'.
Source
Thrown at rust/cubesql/pg-srv/src/values/timestamp.rs:44
pub struct TimestampValue {
unix_nano: i64,
tz: Option<String>,
}
impl TimestampValue {
pub fn new(mut unix_nano: i64, tz: Option<String>) -> TimestampValue {
// This is a hack to workaround a mismatch between on-disk and in-memory representations.
// We use microsecond precision on-disk.
unix_nano -= unix_nano % 1000;
TimestampValue { unix_nano, tz }
}
pub fn to_naive_datetime(&self) -> NaiveDateTime {
// Convert nanoseconds to seconds and nanoseconds
let secs = self.unix_nano / 1_000_000_000;
let nsecs = (self.unix_nano % 1_000_000_000) as u32;
DateTime::from_timestamp(secs, nsecs)
.unwrap_or_else(|| panic!("Invalid timestamp: {}", self.unix_nano))
.naive_utc()
}
pub fn to_fixed_datetime(&self) -> io::Result<DateTime<Tz>> {
assert!(self.tz.is_some());
let tz = self
.tz
.as_ref()
.unwrap()
.parse::<Tz>()
.map_err(|err| io::Error::other(err.to_string()))?;
let ndt = self.to_naive_datetime();
Ok(tz.from_utc_datetime(&ndt))
}
pub fn tz_ref(&self) -> &Option<String> {
&self.tz
}View on GitHub (pinned to 7d981676b3)
Solutions
- Fix the data or the query to return timestamps within the supported range (approximately 1677-2262)
- Check unit conversion upstream — the value is likely seconds or milliseconds mistaken for nanoseconds
- Clamp or sanitize sentinel values (e.g. '9999-12-31') before they reach CubeSQL
Example fix
// before SELECT expire_at FROM tokens -- expire_at = 9999-12-31 // after SELECT CAST(expire_at AS TIMESTAMP) AS expire_at FROM tokens -- keep values within 1677-2262
Defensive patterns
Strategy: validation
Validate before calling
const MIN_NANO: i64 = -9_223_286_400 * 1_000_000_000 / 10; // ~1677
const MAX_NANO: i64 = 9_223_286_400 * 1_000_000_000 / 10; // ~2262
fn timestamp_in_range(unix_nano: i64) -> bool {
(MIN_NANO..=MAX_NANO).contains(&unix_nano)
}
// check before converting bind params or column values
assert!(timestamp_in_range(ts.unix_nano), "timestamp out of chrono range"); Type guard
fn timestamp_in_range(unix_nano: i64) -> bool {
// chrono NaiveDateTime range: ~1677-04-19 to ~2262-04-11
(-9_223_286_400_000_000_000i64 / 10..=9_223_286_400_000_000_000i64 / 10).contains(&unix_nano)
} Prevention
- Confirm epoch unit (s vs ms vs ns) when importing timestamp columns
- Clamp sentinel dates like 9999-12-31 or 1970 epoch-0 sentinels upstream
- Keep business timestamps within ~1677-2262 in the warehouse
When it happens
Trigger: A timestamp value with unix_nano beyond the chrono-supported range is read from a data source or received as a bind parameter and converted via to_naive_datetime (also via to_fixed_datetime/to_text/to_binary).
Common situations: Columns storing epoch-seconds misinterpreted as nanoseconds (values ~1e18 too small/large); sentinel dates like year 0 or 9999; upstream systems writing far-future expiry timestamps.
Related errors
- Should be rewritten with UtcTimestamp function
- This query doesnt have a plan, because it already has values
- CreateExternalTable is not supported
- Explain is not supported
- Analyze is not supported
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/3a41c3a90d4b9fe7.
Report an issue: GitHub.