{"record":{"id":"f479c1607dd352a7","repo":"apache/beam","slug":"empty-timestamp","errorCode":null,"errorMessage":"Empty timestamp.","messagePattern":"Empty timestamp\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsub/PubsubClient.java","lineNumber":87,"sourceCode":"        PubsubOptions options,\n        @Nullable String rootUrlOverride)\n        throws IOException;\n\n    PubsubClient newClient(\n        @Nullable String timestampAttribute, @Nullable String idAttribute, PubsubOptions options)\n        throws IOException;\n\n    /** Return the display name for this factory. Eg \"Json\", \"gRPC\". */\n    String getKind();\n  }\n\n  /**\n   * Return timestamp as ms-since-unix-epoch corresponding to {@code timestamp}. Throw {@link\n   * IllegalArgumentException} if timestamp cannot be recognized.\n   */\n  protected static long parseTimestampAsMsSinceEpoch(String timestamp) {\n    if (timestamp.isEmpty()) {\n      throw new IllegalArgumentException(\"Empty timestamp.\");\n    }\n    try {\n      // Try parsing as milliseconds since epoch. Note there is no way to parse a\n      // string in RFC 3339 format here.\n      // Expected IllegalArgumentException if parsing fails; we use that to fall back\n      // to RFC 3339.\n      return Long.parseLong(timestamp);\n    } catch (IllegalArgumentException e1) {\n      // Try parsing as RFC3339 string. DateTime.parseRfc3339 will throw an\n      // IllegalArgumentException if parsing fails, and the caller should handle.\n      return DateTime.parseRfc3339(timestamp).getValue();\n    }\n  }\n\n  /**\n   * Return the timestamp (in ms since unix epoch) to use for a Pubsub message with {@code\n   * timestampAttribute} and {@code attributes}.\n   *","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsub/PubsubClient.java#L69-L105","documentation":"parseTimestampAsMsSinceEpoch converts a timestamp attribute string to epoch millis. An empty attribute value cannot be parsed as a timestamp, so an IllegalArgumentException is thrown immediately rather than attempting numeric or RFC 3339 parsing.","triggerScenarios":"PubsubIO.read with a timestampAttribute configured; a pulled message contains the timestamp attribute but its value is the empty string; extractTimestampAttribute delegates to parseTimestampAsMsSinceEpoch.","commonSituations":"Producers writing the attribute with an empty value (e.g. empty env var or missing field rendered as \"\"); attribute set but never populated; upstream system clearing the field.","solutions":["Fix the producer to emit a valid millisecond-epoch or RFC 3339 timestamp value","Skip or drop messages whose timestamp attribute is empty in an earlier transform","Use Pub/Sub server-side publishTime (omit timestampAttribute) instead of a custom attribute","Guard the attribute at publish time: only set it when a non-empty value is available"],"exampleFix":"// before\nattributes.put(\"event_time\", maybeNullTimestamp == null ? \"\" : maybeNullTimestamp);\n// after\nif (maybeNullTimestamp != null) {\n  attributes.put(\"event_time\", Long.toString(maybeNullTimestamp));\n}","handlingStrategy":"validation","validationCode":"if (timestampAttr == null || timestampAttr.isEmpty()) {\n  throw new IllegalArgumentException(\"timestamp attribute must be a non-empty epoch-millis or RFC3339 string\");\n}\nLong.parseLong(timestampAttr); // sanity check","typeGuard":"boolean validTimestamp(String ts) { return ts != null && !ts.isEmpty() && (ts.matches(\"\\\\d+\") || isValidRfc3339(ts)); }","tryCatchPattern":"try { long ts = parseTimestampAsMsSinceEpoch(attr); } catch (IllegalArgumentException e) { /* fall back to publishTime or drop message */ }","preventionTips":["Never publish empty timestamp attribute values; omit the attribute instead","Prefer server publishTime when no reliable custom attribute exists","Contract-test producers for the timestamp attribute format","Validate attributes at the producer boundary"],"tags":["java","pubsub","timestamp","attribute","parsing"],"backgroundTag":"invalid-date-format","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-15T02:17:10.978Z"}