apache/beam · error · IllegalArgumentException

throttleDelaySecs must be greater than 0

Error message

throttleDelaySecs must be greater than 0

What it means

ReactiveThrottler extends AdaptiveThrottler and adds a shared throttling signal with a fixed delay; its constructor rejects throttleDelaySecs <= 0 with an IllegalArgumentException. The delay is how long clients back off after an overloaded signal is observed, so a zero or negative delay is nonsensical. The check runs after the superclass overloadRatio validation.

Source

Thrown at sdks/java/io/components/src/main/java/org/apache/beam/sdk/io/components/throttling/ReactiveThrottler.java:59

  /**
   * Initializes the ReactiveThrottler.
   *
   * @param samplePeriodMs length of history to consider, in ms, to set throttling.
   * @param sampleUpdateMs granularity of time buckets that we store data in, in ms.
   * @param overloadRatio the target ratio between requests sent and successful requests.
   * @param namespace the namespace to use for logging and signaling throttling is occurring.
   * @param throttleDelaySecs the amount of time in seconds to wait after preemptively throttled
   *     requests.
   */
  public ReactiveThrottler(
      long samplePeriodMs,
      long sampleUpdateMs,
      double overloadRatio,
      String namespace,
      int throttleDelaySecs) {
    super(samplePeriodMs, sampleUpdateMs, overloadRatio);
    if (throttleDelaySecs <= 0) {
      throw new IllegalArgumentException("throttleDelaySecs must be greater than 0");
    }
    this.throttlingSignaler = new ThrottlingSignaler(namespace);
    this.throttleDelaySecs = throttleDelaySecs;
  }

  /**
   * Stops request code from advancing while the underlying AdaptiveThrottler is signaling to
   * preemptively throttle the request. Automatically handles logging the throttling and signaling
   * to the SDK harness that the request is being throttled. This should be called in any context
   * where a call to a remote service is being contacted prior to the call being performed.
   */
  public void throttle() throws InterruptedException {
    if (throttleRequest(System.currentTimeMillis())) {
      LOG.debug("Delaying request for {} seconds due to previous failures", throttleDelaySecs);
      Thread.sleep(throttleDelaySecs * SECONDS_TO_MILLISECONDS);
      throttlingSignaler.signalThrottling(throttleDelaySecs * SECONDS_TO_MILLISECONDS);
    }
  }

View on GitHub (pinned to 12126d8942)

Solutions

  1. Pass a positive throttleDelaySecs (e.g. 30 for a 30-second back off).
  2. Clamp or default the config value before constructing: throttleDelaySecs <= 0 ? 30 : throttleDelaySecs.
  3. Verify constructor argument order so the delay parameter isn't receiving another value.

Example fix

// before
ReactiveThrottler t = new ReactiveThrottler(1000, 100, 1.3, "myApi", 0);
// after
ReactiveThrottler t = new ReactiveThrottler(1000, 100, 1.3, "myApi", 30);
Defensive patterns

Strategy: validation

Validate before calling

if (throttleDelaySecs <= 0) throw new IllegalArgumentException("throttleDelaySecs must be > 0");
ReactiveThrottler t = new ReactiveThrottler(1000, 100, 1.3, namespace, throttleDelaySecs);

Try / catch

try { new ReactiveThrottler(sp, su, or, ns, delay); } catch (IllegalArgumentException e) { delay = 30; /* fall back to sane delay */ }

Prevention

When it happens

Trigger: Calling new ReactiveThrottler(samplePeriodMs, sampleUpdateMs, overloadRatio, namespace, throttleDelaySecs) with throttleDelaySecs <= 0, e.g. 0 or -1.

Common situations: Passing 0 hoping for 'no delay'; loading the value from config where it defaults to 0; accidentally swapping argument order so throttleDelaySecs receives a negative/zero value.

Related errors


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