vectordotdev/vector · error

invalid timestamp

Error message

invalid timestamp

What it means

table_to_timestamp (lib/vector-core/src/event/lua/util.rs) converts a Lua table with year/month/day/hour/min/sec/nanosec fields into a DateTime<Utc> using chrono's with_ymd_and_hms(...).single().expect("invalid timestamp"). If the components do not form a real instant, single() returns None (ambiguous or non-existent, e.g. Feb 30, month 13, hour 25) or with_nanosecond fails on nano > 999,999,999, and the expect panics inside the Lua/wasmtime host function.

Source

Thrown at lib/vector-core/src/event/lua/util.rs:61

/// This function will fail if the table is malformed.
///
/// # Panics
///
/// Panics if the resulting timestamp is invalid.
#[allow(clippy::needless_pass_by_value)] // constrained by mlua types
pub fn table_to_timestamp(t: LuaTable) -> LuaResult<DateTime<Utc>> {
    let year = t.raw_get("year")?;
    let month = t.raw_get("month")?;
    let day = t.raw_get("day")?;
    let hour = t.raw_get("hour")?;
    let min = t.raw_get("min")?;
    let sec = t.raw_get("sec")?;
    let nano = t.raw_get::<Option<u32>>("nanosec")?.unwrap_or(0);
    Ok(Utc
        .with_ymd_and_hms(year, month, day, hour, min, sec)
        .single()
        .and_then(|t| t.with_nanosecond(nano))
        .expect("invalid timestamp"))
}

View on GitHub (pinned to 3708c39b12)

Solutions

  1. Clamp and validate components in the Lua script before building the table: 1<=month<=12, day valid for that month/year, hour<=23, min/sec<=59, nanosec<1e9
  2. Do the date math with a proper library: return epoch seconds/float from Lua and construct the timestamp on the Rust side, or use parse_timestamp in VRL instead of hand-built tables
  3. Add a Lua-side guard that returns nil / an error string for impossible dates instead of passing them to the host function

Example fix

-- before (lua transform)
local ts = { year = y, month = m, day = d + 1, hour = h, min = mi, sec = s }

-- after: normalize via os.time then rebuild
local tmp = os.date("*t", os.time({ year = y, month = m, day = d, hour = h, min = mi, sec = s }) + 86400)
local ts = { year = tmp.year, month = tmp.month, day = tmp.day, hour = tmp.hour, min = tmp.min, sec = tmp.sec }
Defensive patterns

Strategy: validation

Validate before calling

-- Lua-side guard before building the timestamp table
local function valid_ts(t)
    return t.month >= 1 and t.month <= 12
       and t.day >= 1 and t.day <= 31
       and t.hour >= 0 and t.hour <= 23
       and t.min >= 0 and t.min <= 59
       and t.sec >= 0 and t.sec <= 59
       and (t.nanosec or 0) < 1000000000
end
if not valid_ts(ts) then error("invalid timestamp components") end

Prevention

When it happens

Trigger: A Lua transform (or lua VRL-adjacent host call) returning/constructing a timestamp table with out-of-range or impossible values: month=13, day=31 in a 30-day month, hour=24, min=60, sec=61 (no leap second support), or nanosec >= 1_000_000_000. chrono returns None from .single() (or two values would also be None via single) and the expect fires.

Common situations: Lua transform scripts doing date arithmetic by hand (e.g. day = day + 1 rolling past month end), copying 'sec=60' from syslog-style data, parsing timestamps from logs whose fields were never validated, or timezone/DST edge handling done manually in Lua.

Related errors


AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20). Data as JSON: /api/errors/41b390482942f1d5. Report an issue: GitHub.