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

  1. Fix the emulator or fake to emit well-formed protobuf Timestamps (nanos < 1e9)
  2. Patch Vector: use .and_then instead of .map + expect so a bad publish_time degrades to 'no timestamp' instead of panicking
  3. 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

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


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