{"record":{"id":"7d43a466972e1f6e","repo":"apache/beam","slug":"time-unit-cannot-be-null-when-max-staleness-or-exact","errorCode":null,"errorMessage":"Time unit cannot be null when MAX_STALENESS or EXACT_STALENESS mode is selected","messagePattern":"Time unit cannot be null when MAX_STALENESS or EXACT_STALENESS mode is selected","errorType":"validation","errorClass":"NullPointerException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerTransformRegistrar.java","lineNumber":202,"sourceCode":"        this.staleness = staleness;\n      }\n\n      private @Nullable TimestampBound getTimestampBound() {\n        if (timestampBoundMode == null) {\n          return null;\n        }\n        TimestampBound.Mode mode = TimestampBound.Mode.valueOf(timestampBoundMode);\n        switch (mode) {\n          case STRONG:\n            return TimestampBound.strong();\n          case MAX_STALENESS:\n          case EXACT_STALENESS:\n            if (staleness == null) {\n              throw new NullPointerException(\n                  \"Staleness value cannot be empty when MAX_STALENESS or EXACT_STALENESS mode is selected\");\n            }\n            if (timeUnit == null) {\n              throw new NullPointerException(\n                  \"Time unit cannot be null when MAX_STALENESS or EXACT_STALENESS mode is selected\");\n            }\n            return mode == MAX_STALENESS\n                ? TimestampBound.ofMaxStaleness(staleness, TimeUnit.valueOf(timeUnit))\n                : TimestampBound.ofExactStaleness(staleness, TimeUnit.valueOf(timeUnit));\n          case READ_TIMESTAMP:\n          case MIN_READ_TIMESTAMP:\n            if (readTimestamp == null) {\n              throw new NullPointerException(\n                  \"Timestamp cannot be null when READ_TIMESTAMP or MIN_READ_TIMESTAMP mode is selected\");\n            }\n            return mode == READ_TIMESTAMP\n                ? TimestampBound.ofReadTimestamp(Timestamp.parseTimestamp(readTimestamp))\n                : TimestampBound.ofMinReadTimestamp(Timestamp.parseTimestamp(readTimestamp));\n          default:\n            throw new IllegalArgumentException(\"Unknown timestamp bound mode: \" + mode);\n        }\n      }","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/SpannerTransformRegistrar.java#L184-L220","documentation":"getTimestampBound() requires a TimeUnit whenever the Spanner read mode is MAX_STALENESS or EXACT_STALENESS; the staleness number alone is not a duration. This NullPointerException is thrown when timeUnit is null, because TimestampBound.ofMaxStaleness/ofExactStaleness needs (long, TimeUnit).","triggerScenarios":"Setting mode MAX_STALENESS or EXACT_STALENESS with a staleness value but no time unit (withTimeUnit not called, or the timeUnit field missing/blank in external configuration).","commonSituations":"Config files where staleness was added as \"10\" but the unit key was forgotten; programmatic builders copying another mode's setup; invalid unit strings would also fail later at TimeUnit.valueOf, so ensure exact JDK unit names.","solutions":["Call .withTimeUnit(\"SECONDS\") (or another valid java.util.concurrent.TimeUnit name) alongside the staleness value.","Verify the unit string is a valid TimeUnit enum constant (NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS).","Use STRONG mode if you don't need bounded staleness."],"exampleFix":"// before\n.withTimestampBoundMode(\"EXACT_STALENESS\").withStaleness(15)\n// after\n.withTimestampBoundMode(\"EXACT_STALENESS\").withStaleness(15).withTimeUnit(\"SECONDS\")","handlingStrategy":"validation","validationCode":"if ((mode == TimestampBoundMode.MAX_STALENESS || mode == TimestampBoundMode.EXACT_STALENESS) && timeUnit == null) { throw new IllegalArgumentException(mode + \" requires a TimeUnit\"); }","typeGuard":null,"tryCatchPattern":"try { TimeUnit u = TimeUnit.valueOf(config.getTimeUnit()); } catch (NullPointerException | IllegalArgumentException e) { throw new ConfigException(\"Invalid or missing timeUnit: \" + config.getTimeUnit(), e); }","preventionTips":["Parse the unit with TimeUnit.valueOf up front and fail with a clear message on bad input.","Pair staleness and unit in one setter/helper so they cannot diverge.","List accepted unit names in your config schema documentation."],"tags":["java","apache-beam","google-cloud-spanner","null-check","time-unit"],"backgroundTag":"null-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}