apache/beam · error · NullPointerException

Staleness value cannot be empty when MAX_STALENESS or EXACT_

Error message

Staleness value cannot be empty when MAX_STALENESS or EXACT_STALENESS mode is selected

What it means

getTimestampBound() builds a Cloud Spanner TimestampBound for stale reads based on the configured read mode. When the mode is MAX_STALENESS or EXACT_STALENESS, both a staleness numeric value and a time unit are required; this NullPointerException is thrown when staleness is null, because Spanner's ofMaxStaleness/ofExactStaleness cannot be invoked without a duration.

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerTransformRegistrar.java:198

        this.timeUnit = timeUnit;
      }

      public void setStaleness(@Nullable Long staleness) {
        this.staleness = staleness;
      }

      private @Nullable TimestampBound getTimestampBound() {
        if (timestampBoundMode == null) {
          return null;
        }
        TimestampBound.Mode mode = TimestampBound.Mode.valueOf(timestampBoundMode);
        switch (mode) {
          case STRONG:
            return TimestampBound.strong();
          case MAX_STALENESS:
          case EXACT_STALENESS:
            if (staleness == null) {
              throw new NullPointerException(
                  "Staleness value cannot be empty when MAX_STALENESS or EXACT_STALENESS mode is selected");
            }
            if (timeUnit == null) {
              throw new NullPointerException(
                  "Time unit cannot be null when MAX_STALENESS or EXACT_STALENESS mode is selected");
            }
            return mode == MAX_STALENESS
                ? TimestampBound.ofMaxStaleness(staleness, TimeUnit.valueOf(timeUnit))
                : TimestampBound.ofExactStaleness(staleness, TimeUnit.valueOf(timeUnit));
          case READ_TIMESTAMP:
          case MIN_READ_TIMESTAMP:
            if (readTimestamp == null) {
              throw new NullPointerException(
                  "Timestamp cannot be null when READ_TIMESTAMP or MIN_READ_TIMESTAMP mode is selected");
            }
            return mode == READ_TIMESTAMP
                ? TimestampBound.ofReadTimestamp(Timestamp.parseTimestamp(readTimestamp))
                : TimestampBound.ofMinReadTimestamp(Timestamp.parseTimestamp(readTimestamp));

View on GitHub (pinned to 12126d8942)

Solutions

  1. Provide the staleness value together with the mode (e.g. staleness=10, timeUnit=SECONDS).
  2. If you don't want stale reads, switch the mode to STRONG instead.
  3. Add a pre-build check that (mode==MAX_STALENESS||mode==EXACT_STALENESS) implies staleness!=null.

Example fix

// before
.withTimestampBoundMode("MAX_STALENESS")
// after
.withTimestampBoundMode("MAX_STALENESS").withStaleness(10).withTimeUnit("SECONDS")
Defensive patterns

Strategy: validation

Validate before calling

if ((mode == TimestampBoundMode.MAX_STALENESS || mode == TimestampBoundMode.EXACT_STALENESS) && staleness == null) { throw new IllegalArgumentException(mode + " requires a staleness value"); }

Try / catch

try { TimestampBound tb = config.timestampBound(); } catch (NullPointerException e) { throw new ConfigException("staleness/timeUnit/readTimestamp missing for mode " + config.mode, e); }

Prevention

When it happens

Trigger: Setting read mode to MAX_STALENESS or EXACT_STALENESS (e.g. withReadTime("MAX_STALENESS") or via external configuration) but leaving the staleness value unset/null in the ReadBuilder/ChangeStreamReaderBuilder configuration.

Common situations: YAML/JSON external pipeline specs that set the mode but omit the staleness field; CLI options where the staleness flag was not passed; defaults where mode changed to staleness-based without updating the value.

Related errors


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