apache/beam · error · IllegalArgumentException

Empty timestamp.

Error message

Empty timestamp.

What it means

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.

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/pubsub/PubsubClient.java:87

        PubsubOptions options,
        @Nullable String rootUrlOverride)
        throws IOException;

    PubsubClient newClient(
        @Nullable String timestampAttribute, @Nullable String idAttribute, PubsubOptions options)
        throws IOException;

    /** Return the display name for this factory. Eg "Json", "gRPC". */
    String getKind();
  }

  /**
   * Return timestamp as ms-since-unix-epoch corresponding to {@code timestamp}. Throw {@link
   * IllegalArgumentException} if timestamp cannot be recognized.
   */
  protected static long parseTimestampAsMsSinceEpoch(String timestamp) {
    if (timestamp.isEmpty()) {
      throw new IllegalArgumentException("Empty timestamp.");
    }
    try {
      // Try parsing as milliseconds since epoch. Note there is no way to parse a
      // string in RFC 3339 format here.
      // Expected IllegalArgumentException if parsing fails; we use that to fall back
      // to RFC 3339.
      return Long.parseLong(timestamp);
    } catch (IllegalArgumentException e1) {
      // Try parsing as RFC3339 string. DateTime.parseRfc3339 will throw an
      // IllegalArgumentException if parsing fails, and the caller should handle.
      return DateTime.parseRfc3339(timestamp).getValue();
    }
  }

  /**
   * Return the timestamp (in ms since unix epoch) to use for a Pubsub message with {@code
   * timestampAttribute} and {@code attributes}.
   *

View on GitHub (pinned to 12126d8942)

Solutions

  1. Fix the producer to emit a valid millisecond-epoch or RFC 3339 timestamp value
  2. Skip or drop messages whose timestamp attribute is empty in an earlier transform
  3. Use Pub/Sub server-side publishTime (omit timestampAttribute) instead of a custom attribute
  4. Guard the attribute at publish time: only set it when a non-empty value is available

Example fix

// before
attributes.put("event_time", maybeNullTimestamp == null ? "" : maybeNullTimestamp);
// after
if (maybeNullTimestamp != null) {
  attributes.put("event_time", Long.toString(maybeNullTimestamp));
}
Defensive patterns

Strategy: validation

Validate before calling

if (timestampAttr == null || timestampAttr.isEmpty()) {
  throw new IllegalArgumentException("timestamp attribute must be a non-empty epoch-millis or RFC3339 string");
}
Long.parseLong(timestampAttr); // sanity check

Type guard

boolean validTimestamp(String ts) { return ts != null && !ts.isEmpty() && (ts.matches("\\d+") || isValidRfc3339(ts)); }

Try / catch

try { long ts = parseTimestampAsMsSinceEpoch(attr); } catch (IllegalArgumentException e) { /* fall back to publishTime or drop message */ }

Prevention

When it happens

Trigger: PubsubIO.read with a timestampAttribute configured; a pulled message contains the timestamp attribute but its value is the empty string; extractTimestampAttribute delegates to parseTimestampAsMsSinceEpoch.

Common situations: 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.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/f479c1607dd352a7. Report an issue: GitHub.