apache/beam · error · IllegalArgumentException
timerFrequency must be greater than zero
Error message
timerFrequency must be greater than zero
What it means
AsyncWrapper schedules a timer-driven maintenance tick using a user-supplied timerFrequency Duration. If the duration's milliseconds are zero or negative the timer loop would spin or never fire correctly, so the constructor throws IllegalArgumentException. This validates configuration at pipeline construction time rather than failing at runtime.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/AsyncWrapper.java:197
idFn,
useThreadPool,
null);
}
public AsyncWrapper(
DoFn<InputT, OutputT> syncFn,
int parallelism,
Duration timerFrequency,
@Nullable Integer maxItemsToBuffer,
@Nullable Duration timeout,
@Nullable Duration maxWaitTime,
@Nullable SerializableFunction<InputT, Object> idFn,
boolean useThreadPool,
@Nullable Coder<KV<K, InputT>> coder) {
this.syncFn = syncFn;
this.parallelism = parallelism;
if (timerFrequency.getMillis() <= 0) {
throw new IllegalArgumentException("timerFrequency must be greater than zero");
}
this.timerFrequency = timerFrequency;
this.maxItemsToBuffer =
(maxItemsToBuffer != null)
? maxItemsToBuffer
: Math.max(parallelism * 2, DEFAULT_MIN_BUFFER_CAPACITY);
this.timeout = (timeout != null) ? timeout : Duration.standardSeconds(DEFAULT_TIMEOUT_SEC);
this.maxWaitTime =
(maxWaitTime != null) ? maxWaitTime : Duration.millis(DEFAULT_MAX_WAIT_TIME_MS);
this.idFn =
(idFn != null)
? idFn
: (SerializableFunction<InputT, Object>)
input -> java.util.Objects.requireNonNull(input);
this.useThreadPool = useThreadPool;
this.uuid = UUID.randomUUID().toString();
this.toProcessSpec = (coder != null) ? StateSpecs.bag(coder) : StateSpecs.bag();
}View on GitHub (pinned to 12126d8942)
Solutions
- Pass a positive Duration, e.g. Duration.millis(100) or larger
- Guard config-driven values: if (millis <= 0) millis = defaultTimerFrequencyMillis
- If you want a pure callback-driven design, check whether the wrapper supports disabling timers instead of using 0
Example fix
// before AsyncWrapper.wrap(fn, parallelism).withTimerFrequency(Duration.ZERO); // after AsyncWrapper.wrap(fn, parallelism).withTimerFrequency(Duration.millis(100));
Defensive patterns
Strategy: validation
Validate before calling
if (timerFrequency == null || timerFrequency.getMillis() <= 0) {
timerFrequency = Duration.millis(100);
} Try / catch
try {
builder.withTimerFrequency(freq);
} catch (IllegalArgumentException e) {
builder.withTimerFrequency(Duration.millis(100));
} Prevention
- Never pass Duration.ZERO or negative durations as frequencies
- Validate config files that supply timer values before building the pipeline
- Pick frequencies well above scheduler granularity (>= 10ms)
When it happens
Trigger: Building an AsyncWrapper (via its builder/constructor) with Duration.ZERO, Duration.millis(0), or a negative Duration for timerFrequency.
Common situations: Developers pass Duration.ZERO assuming 'as fast as possible', or compute the duration from config where a 0 default slipped through.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- No filesystem found for scheme
- Exploded field %s must be an iterable type, got %s.
- boolean cross product parameter required to explode more tha
- ${config}
- Unknown log level ${level}. Valid log levels are ${validLeve
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/7f0f8d17ff398a7b.
Report an issue: GitHub.