vectordotdev/vector · error
invalid timestamp
Error message
invalid timestamp
What it means
Each message pulled from Pub/Sub carries an optional publish_time (google.protobuf.Timestamp) that Vector converts with DateTime::from_timestamp(dt.seconds, dt.nanos as u32).expect("invalid timestamp"). from_timestamp returns None when nanoseconds >= 2,000,000,000 or seconds fall outside chrono's range. Google's frontends always emit valid timestamps, so in practice this fires only against a non-Google endpoint that returns malformed protobuf Timestamps.
Source
Thrown at src/sources/gcp_pubsub.rs:687
fn parse_message<'a>(
&'a self,
message: proto::PubsubMessage,
batch: &'a Option<BatchNotifier>,
) -> impl Iterator<Item = Event> + 'a {
let attributes = Value::Object(
message
.attributes
.into_iter()
.map(|(key, value)| (key.into(), Value::Bytes(value.into())))
.collect(),
);
let log_namespace = self.log_namespace;
util::decode_message(
self.decoder.clone(),
"gcp_pubsub",
&message.data,
message.publish_time.map(|dt| {
DateTime::from_timestamp(dt.seconds, dt.nanos as u32).expect("invalid timestamp")
}),
batch,
log_namespace,
&self.events_received,
)
.map(move |mut event| {
if let Some(log) = event.maybe_as_log_mut() {
log_namespace.insert_source_metadata(
PubsubConfig::NAME,
log,
Some(LegacyKey::Overwrite(path!("message_id"))),
path!("message_id"),
message.message_id.clone(),
);
log_namespace.insert_source_metadata(
PubsubConfig::NAME,
log,
Some(LegacyKey::Overwrite(path!("attributes"))),View on GitHub (pinned to 3708c39b12)
Solutions
- Fix the emulator or fake to emit well-formed protobuf Timestamps (nanos < 1e9)
- Patch Vector: use .and_then instead of .map + expect so a bad publish_time degrades to 'no timestamp' instead of panicking
- Verify against real GCP endpoints before trusting an emulator
Example fix
// before
message.publish_time.map(|dt| {
DateTime::from_timestamp(dt.seconds, dt.nanos as u32).expect("invalid timestamp")
}),
// after
message.publish_time.and_then(|dt| {
DateTime::from_timestamp(dt.seconds, dt.nanos as u32)
}), Defensive patterns
Strategy: validation
Validate before calling
fn valid_proto_timestamp(seconds: i64, nanos: u32) -> bool {
(-8_334_601_228_800..=8_210_266_876_799).contains(&seconds) && nanos < 2_000_000_000
}
// before decoding:
if let Some(ref pt) = message.publish_time {
if !valid_proto_timestamp(pt.seconds, pt.nanos as u32) {
warn!(message = "dropping invalid publish_time");
}
} Type guard
fn proto_to_datetime(dt: &prost_types::Timestamp) -> Option<chrono::DateTime<chrono::Utc>> {
chrono::DateTime::from_timestamp(dt.seconds, dt.nanos as u32)
} Try / catch
let publish_time = message
.publish_time
.and_then(|dt| chrono::DateTime::from_timestamp(dt.seconds, dt.nanos as u32));
// None simply means: decode without a timestamp Prevention
- Treat emulator/mock endpoints as untrusted: validate their protobuf fields
- Prefer and_then over map+expect for optional conversions of external data
- Contract-test fakes against real GCP response shapes
When it happens
Trigger: Pointing the source at a Pub/Sub-compatible emulator, proxy, or gRPC test double whose StreamingPullResponse messages carry publish_time with nanos >= 2e9 or absurd seconds values.
Common situations: Local emulators, contract-test fakes, replaying/MITM proxies rewriting responses; unaffected when talking to real Google endpoints.
Related errors
- Timestamp out of range
- invalid timestamp
- target_tps cannot be Nan
- error_tps cannot be Nan
- invalid timestamp
AI-assisted analysis of vectordotdev/vector@3708c39b12 (2026-08-20).
Data as JSON: /api/errors/a915790f8b5952e9.
Report an issue: GitHub.