apache/beam · error · IllegalArgumentException

watermark_column_time_unit '{watermarkColumnTimeUnit}' is in

Error message

watermark_column_time_unit '{watermarkColumnTimeUnit}' is invalid. Please choose one of: {values}

What it means

IcebergScanConfig.validate parses watermark_column_time_unit into java.util.concurrent.TimeUnit. If the configured string (uppercased) is not a TimeUnit constant, IllegalArgumentException is thrown with the valid choices. This validates the watermark column unit before building the scan.

Source

Thrown at sdks/java/io/iceberg/src/main/java/org/apache/beam/sdk/io/iceberg/IcebergScanConfig.java:551

    }

    @Nullable String watermarkColumnTimeUnit = getWatermarkColumnTimeUnit();
    if (watermarkColumnTimeUnit != null) {
      checkArgument(
          table
                  .schema()
                  .findField(
                      checkStateNotNull(
                          watermarkColumn,
                          "watermark_column_time_unit is configured without a specified watermark_column"))
                  .type()
                  .typeId()
              == LONG,
          error("watermark_column_time_unit is only applicable for LONG columns."));
      try {
        TimeUnit.valueOf(watermarkColumnTimeUnit.toUpperCase(Locale.ENGLISH));
      } catch (IllegalArgumentException e) {
        throw new IllegalArgumentException(
            error(
                String.format(
                    "watermark_column_time_unit '%s' is invalid. Please choose one of: %s",
                    watermarkColumnTimeUnit, Arrays.toString(TimeUnit.values()))),
            e);
      }
    }
  }

  private void validateMetadataColumns(Table table) {
    List<String> metadataColumns = getMetadataColumns();
    if (metadataColumns.isEmpty()) {
      return;
    }

    Set<String> uniqueMetadataColumns = new LinkedHashSet<>(metadataColumns);
    checkArgument(
        uniqueMetadataColumns.size() == metadataColumns.size(),

View on GitHub (pinned to 12126d8942)

Solutions

  1. Set watermark_column_time_unit to an exact TimeUnit constant, e.g. MICROSECONDS or SECONDS.
  2. Validate the unit string against TimeUnit values before submitting the pipeline.
  3. Check that the unit matches the actual granularity of the watermark column's LONG values.
  4. Normalize casing in config generation (TimeUnit.valueOf already uppercases, but the name must still match exactly).

Example fix

// before
config.setWatermarkColumnTimeUnit("millis");

// after
config.setWatermarkColumnTimeUnit("MILLISECONDS");
Defensive patterns

Strategy: validation

Validate before calling

boolean valid = unitStr == null
    || Arrays.stream(TimeUnit.values())
        .anyMatch(u -> u.name().equalsIgnoreCase(unitStr));
if (!valid) throw new IllegalArgumentException("invalid watermark_column_time_unit: " + unitStr);

Try / catch

try {
  scanConfig.validate();
} catch (IllegalArgumentException e) {
  LOG.error("Invalid watermark unit: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Setting watermark_column_time_unit to any string that is not one of TimeUnit.values() (NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS) at IcebergScanConfig.java:551.

Common situations: Using lowercase-friendly units like 'micros' or 'seconds' that don't match enum names; units like 'MILLIS' which is not a Java TimeUnit; config generated from documentation for a different library.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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