apache/beam · error · IllegalArgumentException

Cannot output with timestamp

Error message

Cannot output with 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 by the DoFnProcessContext/OutputReceiver when an element is emitted (via OutputReceiver.output or c.outputWithTimestamp) with a timestamp outside the allowed bounds: earlier than the current element's timestamp minus getAllowedTimestampSkew, or later than TIMESTAMP_MAX_VALUE. This enforces Beam's timestamp skew invariant for DoFn outputs in the Fn API harness.

Solutions

  1. Override @GetAllowedTimestampSkew on the DoFn to return a Duration large enough to cover your output timestamps.
  2. Emit with a timestamp >= element timestamp minus allowed skew; clamp the computed timestamp before calling output.
  3. Clamp timestamps to BoundedWindow.TIMESTAMP_MAX_VALUE before emitting.
  4. If the element timestamp itself is wrong, fix upstream timestamp assignment (e.g. watermark/DoFn source) rather than adjusting skew.

Example fix

// before
context.outputWithTimestamp(out, value, eventTime.minus(Duration.standardDays(2)));

// after: declare the skew
@GetAllowedTimestampSkew
public Duration getAllowedTimestampSkew() { return Duration.standardDays(3); }
context.outputWithTimestamp(out, value, eventTime.minus(Duration.standardDays(2)));
Defensive patterns

Strategy: validation

Validate before calling

Instant lowerBound = currentElement.getTimestamp().minus(doFn.getAllowedTimestampSkew());
if (ts.isBefore(lowerBound)) ts = lowerBound;
if (ts.isAfter(BoundedWindow.TIMESTAMP_MAX_VALUE)) ts = BoundedWindow.TIMESTAMP_MAX_VALUE;

Try / catch

try {
  c.outputWithTimestamp(out, value, ts);
} catch (IllegalArgumentException e) {
  // fallback: emit at input timestamp
  c.output(value);
}

Prevention

When it happens

Trigger: Calling c.output(value, timestamp) or c.outputWithTimestamp(tag, value, timestamp) where timestamp.isBefore(currentElement.getTimestamp().minus(allowedSkew)) || timestamp.isAfter(BoundedWindow.TIMESTAMP_MAX_VALUE).

Common situations: Re-timestamping outputs far into the past without declaring a skew; emitting timestamps computed from clock values before the element time; test data with Instant.MAX causing overflow past TIMESTAMP_MAX_VALUE; runners that do not permit arbitrary timestamps (BEAM-29637 semantics).

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/959d05d91b9276d1. Report an issue: GitHub.

Appendix: source

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

          boundedWindow,
          elementTimestampOrTimerHoldTimestamp,
          elementTimestampOrTimerFireTimestamp,
          paneInfo,
          timeDomain);
    }
  }

  @SuppressWarnings("deprecation") // Allowed Skew is deprecated for users, but must be respected
  private void checkTimestamp(Instant timestamp) {
    Instant lowerBound;
    try {
      lowerBound = currentElement.getTimestamp().minus(doFn.getAllowedTimestampSkew());
    } catch (ArithmeticException e) {
      lowerBound = BoundedWindow.TIMESTAMP_MIN_VALUE;
    }

    if (timestamp.isBefore(lowerBound) || timestamp.isAfter(BoundedWindow.TIMESTAMP_MAX_VALUE)) {
      throw new IllegalArgumentException(
          String.format(
              "Cannot output with 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.",
              timestamp,
              currentElement.getTimestamp(),
              doFn.getAllowedTimestampSkew().getMillis() >= Integer.MAX_VALUE
                  ? doFn.getAllowedTimestampSkew()
                  : PeriodFormat.getDefault().print(doFn.getAllowedTimestampSkew().toPeriod()),
              BoundedWindow.TIMESTAMP_MAX_VALUE));
    }
  }

  private class StartBundleArgumentProvider extends BaseArgumentProvider<InputT, OutputT> {
    private class Context extends DoFn<InputT, OutputT>.StartBundleContext {
      Context() {
        doFn.super();

View on GitHub (pinned to 12126d8942)