apache/beam · error · IllegalArgumentException

Cannot output timer with output timestamp

Error message

Cannot output timer with output timestamp %s. Output timestamps must be no earlier than the timestamp of the current input (%s) minus the allowed skew (%s) and no later than %s. See the DoFn#getAllowedTimestampSkew() Javadoc for details on changing the allowed skew.

What it means

Thrown when a DoFn sets a timer with an output timestamp that falls outside the permitted window: it must not be earlier than the current input (or timer hold) timestamp minus the DoFn's allowed timestamp skew, and not later than BoundedWindow.TIMESTAMP_MAX_VALUE. This enforces the DoFn#getAllowedTimestampSkew contract in the Fn API harness.

Solutions

  1. Return a larger value from DoFn#getAllowedTimestampSkew() (e.g. Duration.standardHours(1)) so the lower bound covers your timer timestamps.
  2. Clamp the timer's output timestamp to be >= input timestamp minus allowed skew before setting it.
  3. Ensure the timer timestamp is not after BoundedWindow.TIMESTAMP_MAX_VALUE; clamp to that constant if needed.
  4. Verify arithmetic on Instant timestamps (minus/add) isn't overflowing; the harness clamps overflow but the resulting comparison can still fail.

Example fix

// before
@GetAllowedTimestampSkew
public Duration getAllowedTimestampSkew() { return Duration.ZERO; }
timer.offset(Duration.standardMinutes(-30));

// after
@GetAllowedTimestampSkew
public Duration getAllowedTimestampSkew() { return Duration.standardHours(1); }
Defensive patterns

Strategy: validation

Validate before calling

Duration skew = doFn.getAllowedTimestampSkew();
Instant lower = inputTs.minus(skew);
if (timerTs.isBefore(lower) || timerTs.isAfter(BoundedWindow.TIMESTAMP_MAX_VALUE)) {
  timerTs = max(timerTs, lower); // clamp before setting
}

Try / catch

try {
  timer.offset(d);
} catch (IllegalArgumentException e) {
  throw new IllegalStateException("Timer timestamp outside allowed skew; increase @GetAllowedTimestampSkew", e);
}

Prevention

When it happens

Trigger: Calling Timer.set(...)/offset/onTimer callbacks where the computed output timestamp is before inputTimestamp.minus(allowedTimestampSkew) or after TIMESTAMP_MAX_VALUE, inside a timer-aware DoFn executed by FnApiDoFnRunner.

Common situations: Setting a timer with a timestamp far in the past relative to the element's timestamp; using Instant.minus() that under/overflows; overriding getAllowedTimestampSkew with a small value while emitting early timestamps; windowing edge cases near the timestamp min/max bounds.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java:1450

      return target;
    }

    private Timer<K> getClearedTimer() {
      return Timer.cleared(userKey, dynamicTimerTag, Collections.singletonList(boundedWindow));
    }

    @SuppressWarnings("deprecation") // Allowed Skew is deprecated for users, but must be respected
    private Timer<K> getTimerForTime(Instant scheduledTime) {
      if (outputTimestamp != null) {
        Instant lowerBound;
        try {
          lowerBound = elementTimestampOrTimerHoldTimestamp.minus(doFn.getAllowedTimestampSkew());
        } catch (ArithmeticException e) {
          lowerBound = BoundedWindow.TIMESTAMP_MIN_VALUE;
        }
        if (outputTimestamp.isBefore(lowerBound)
            || outputTimestamp.isAfter(BoundedWindow.TIMESTAMP_MAX_VALUE)) {
          throw new IllegalArgumentException(
              String.format(
                  "Cannot output timer with output timestamp %s. Output timestamps must be no "
                      + "earlier than the timestamp of the current input (%s) minus the allowed skew "
                      + "(%s) and no later than %s. See the DoFn#getAllowedTimestampSkew() Javadoc for "
                      + "details on changing the allowed skew.",
                  outputTimestamp,
                  elementTimestampOrTimerHoldTimestamp,
                  doFn.getAllowedTimestampSkew().getMillis() >= Integer.MAX_VALUE
                      ? doFn.getAllowedTimestampSkew()
                      : PeriodFormat.getDefault().print(doFn.getAllowedTimestampSkew().toPeriod()),
                  BoundedWindow.TIMESTAMP_MAX_VALUE));
        }
      }

      // Output timestamp is set to the delivery time if not initialized by an user.
      if (!noOutputTimestamp
          && outputTimestamp == null
          && TimeDomain.EVENT_TIME.equals(timeDomain)) {

View on GitHub (pinned to 12126d8942)