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
- Provide the staleness value together with the mode (e.g. staleness=10, timeUnit=SECONDS).
- If you don't want stale reads, switch the mode to STRONG instead.
- 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
- Model staleness as a required field whenever the mode is staleness-based (schema-level validation).
- Default to STRONG mode when no staleness is configured.
- Validate the full (mode, staleness, timeUnit) triple before building the transform.
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
- Time unit cannot be null when MAX_STALENESS or EXACT_STALENE
- Timestamp cannot be null when READ_TIMESTAMP or MIN_READ_TIM
- lenientFormat(errorMessageTemplate, p1, p2)
- Can't compare %s with NULL
- databaseId can't be empty
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/0d8c0b0481ca3d8a.
Report an issue: GitHub.