{"record":{"id":"a915790f8b5952e9","repo":"vectordotdev/vector","slug":"invalid-timestamp-a91579","errorCode":null,"errorMessage":"invalid timestamp","messagePattern":"invalid timestamp","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/sources/gcp_pubsub.rs","lineNumber":687,"sourceCode":"    fn parse_message<'a>(\n        &'a self,\n        message: proto::PubsubMessage,\n        batch: &'a Option<BatchNotifier>,\n    ) -> impl Iterator<Item = Event> + 'a {\n        let attributes = Value::Object(\n            message\n                .attributes\n                .into_iter()\n                .map(|(key, value)| (key.into(), Value::Bytes(value.into())))\n                .collect(),\n        );\n        let log_namespace = self.log_namespace;\n        util::decode_message(\n            self.decoder.clone(),\n            \"gcp_pubsub\",\n            &message.data,\n            message.publish_time.map(|dt| {\n                DateTime::from_timestamp(dt.seconds, dt.nanos as u32).expect(\"invalid timestamp\")\n            }),\n            batch,\n            log_namespace,\n            &self.events_received,\n        )\n        .map(move |mut event| {\n            if let Some(log) = event.maybe_as_log_mut() {\n                log_namespace.insert_source_metadata(\n                    PubsubConfig::NAME,\n                    log,\n                    Some(LegacyKey::Overwrite(path!(\"message_id\"))),\n                    path!(\"message_id\"),\n                    message.message_id.clone(),\n                );\n                log_namespace.insert_source_metadata(\n                    PubsubConfig::NAME,\n                    log,\n                    Some(LegacyKey::Overwrite(path!(\"attributes\"))),","sourceCodeStart":669,"sourceCodeEnd":705,"githubUrl":"https://github.com/vectordotdev/vector/blob/3708c39b12a93212ed8b8d7510b4cc7769cb5864/src/sources/gcp_pubsub.rs#L669-L705","documentation":"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.","triggerScenarios":"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.","commonSituations":"Local emulators, contract-test fakes, replaying/MITM proxies rewriting responses; unaffected when talking to real Google endpoints.","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"],"exampleFix":"// before\nmessage.publish_time.map(|dt| {\n    DateTime::from_timestamp(dt.seconds, dt.nanos as u32).expect(\"invalid timestamp\")\n}),\n\n// after\nmessage.publish_time.and_then(|dt| {\n    DateTime::from_timestamp(dt.seconds, dt.nanos as u32)\n}),","handlingStrategy":"validation","validationCode":"fn valid_proto_timestamp(seconds: i64, nanos: u32) -> bool {\n    (-8_334_601_228_800..=8_210_266_876_799).contains(&seconds) && nanos < 2_000_000_000\n}\n\n// before decoding:\nif let Some(ref pt) = message.publish_time {\n    if !valid_proto_timestamp(pt.seconds, pt.nanos as u32) {\n        warn!(message = \"dropping invalid publish_time\");\n    }\n}","typeGuard":"fn proto_to_datetime(dt: &prost_types::Timestamp) -> Option<chrono::DateTime<chrono::Utc>> {\n    chrono::DateTime::from_timestamp(dt.seconds, dt.nanos as u32)\n}","tryCatchPattern":"let publish_time = message\n    .publish_time\n    .and_then(|dt| chrono::DateTime::from_timestamp(dt.seconds, dt.nanos as u32));\n// None simply means: decode without a timestamp","preventionTips":["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"],"tags":["rust","panic","protobuf","timestamp","gcp-pubsub","emulator"],"backgroundTag":"timestamp-out-of-range","analyzedSha":"3708c39b12a93212ed8b8d7510b4cc7769cb5864","analyzedAt":"2026-08-20T07:02:18.786Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}