vectordotdev/vector · critical
invalid timestamp
Error message
invalid timestamp
What it means
The journald source consumes the journalctl export format; timestamp fields such as __REALTIME_TIMESTAMP arrive as microsecond strings parsed to u64, then chrono::Utc.timestamp_opt(ts / 1_000_000, ts % 1_000_000 * 1_000).single().expect("invalid timestamp"). Microsecond values beyond chrono's representable window (about 8.2e18 microseconds, year ~262143) make single() return None and the expect panics the source task.
Source
Thrown at src/sources/journald.rs:883
LogNamespace::Vector => log
.get(metadata_path!(JournaldConfig::NAME, "metadata"))
.and_then(|meta| {
meta.get(path!(SOURCE_TIMESTAMP))
.or_else(|| meta.get(path!(RECEIVED_TIMESTAMP)))
}),
LogNamespace::Legacy => log
.get(event_path!(SOURCE_TIMESTAMP))
.or_else(|| log.get(event_path!(RECEIVED_TIMESTAMP))),
};
let timestamp = timestamp_value
.filter(|&ts| ts.is_bytes())
.and_then(|ts| ts.as_str().unwrap().parse::<u64>().ok())
.map(|ts| {
chrono::Utc
.timestamp_opt((ts / 1_000_000) as i64, (ts % 1_000_000) as u32 * 1_000)
.single()
.expect("invalid timestamp")
});
// Add timestamp.
match log_namespace {
LogNamespace::Vector => {
log.insert(metadata_path!("vector", "ingest_timestamp"), Utc::now());
if let Some(ts) = timestamp {
log.insert(metadata_path!(JournaldConfig::NAME, "timestamp"), ts);
}
}
LogNamespace::Legacy => {
if let Some(ts) = timestamp {
log.maybe_insert(log_schema().timestamp_key_target_path(), ts);
}
}
}
View on GitHub (pinned to 3708c39b12)
Solutions
- Sanitize or bound the producer's timestamp fields before they reach Vector
- Patch: match on .single() (or pre-filter ts) and skip events with out-of-range timestamps, with a warning
- Upgrade Vector once graceful handling lands
Example fix
// before
.map(|ts| {
chrono::Utc
.timestamp_opt((ts / 1_000_000) as i64, (ts % 1_000_000) as u32 * 1_000)
.single()
.expect("invalid timestamp")
});
// after
.and_then(|ts| {
chrono::Utc
.timestamp_opt((ts / 1_000_000) as i64, (ts % 1_000_000) as u32 * 1_000)
.single()
})
// and, if preferred, log when the result is None instead of silently dropping Defensive patterns
Strategy: validation
Validate before calling
const MAX_VALID_MICROS: u64 = 8_210_266_876_799_000_000; // ~chrono max
fn valid_journald_micros(ts: u64) -> bool {
ts <= MAX_VALID_MICROS
}
// before parsing:
if !valid_journald_micros(ts) {
warn!(message = "dropping event with out-of-range journal timestamp", ts);
return None;
} Type guard
fn journal_micros_to_datetime(ts: u64) -> Option<chrono::DateTime<chrono::Utc>> {
chrono::Utc
.timestamp_opt((ts / 1_000_000) as i64, (ts % 1_000_000) as u32 * 1_000)
.single()
} Try / catch
let timestamp = timestamp_value.and_then(|ts| {
chrono::Utc
.timestamp_opt((ts / 1_000_000) as i64, (ts % 1_000_000) as u32 * 1_000)
.single()
});
// None: proceed without a source timestamp and log at debug/warn Prevention
- Sanitize replayed/fuzzed journal export data before feeding it to Vector
- Bound u64 timestamp fields at the ingest boundary
- Never expect() on parsed external numeric fields
- Add fixture tests with extreme timestamp values to the journald source
When it happens
Trigger: Feeding the journald source a crafted or corrupt export stream (or HTTP/gRPC payload in that format) whose timestamp field is a huge u64 such as u64::MAX, or placeholder/sentinel test values; healthy systemd journals never produce them.
Common situations: Replaying captured or fuzzed journal exports, custom journald forwarders, test fixtures with sentinel timestamps.
Related errors
- Timestamp out of range
- invalid timestamp
- invalid timestamp
- path and query should never fail to parse
- Serializer does not support JSON
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/6376b24194efb3ae.
Report an issue: GitHub.