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
- Set watermark_column_time_unit to an exact TimeUnit constant, e.g. MICROSECONDS or SECONDS.
- Validate the unit string against TimeUnit values before submitting the pipeline.
- Check that the unit matches the actual granularity of the watermark column's LONG values.
- 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
- Use exact TimeUnit constant names (e.g. MICROSECONDS, not 'micros').
- Validate unit strings at config load time.
- Match the unit to the watermark column's actual LONG granularity.
- Generate config values from TimeUnit.values() rather than prose.
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
- the following options are currently only available when read
- Unknown scan type: {}
- Unexpected logical type: {}
- Unsupported CDC ValueKind: {}
- Unrecognized value for stable unique names:
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/ebbffeb9719b9852.
Report an issue: GitHub.