apache/beam · error · IllegalStateException

Received timer after inbound timer receiver is done for inst

Error message

Received timer after inbound timer receiver is done for instruction %s, transform %s, and timer family %s.

What it means

multiplexElements throws IllegalStateException when timers arrive for an (instruction, transform, timerFamily) endpoint that is already marked done. The timer endpoint was terminated and late timer data is still arriving for it.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/fn/data/BeamFnDataInboundObserver.java:259

    while (timerElements.hasNext()) {
      Elements.Timers timers = timerElements.next();
      Map<String, EndpointStatus<TimerEndpoint<?>>> timerFamilyIdToEndpoints =
          transformIdToTimerFamilyIdToTimerEndpoint.get(timers.getTransformId());
      if (timerFamilyIdToEndpoints == null) {
        throw new IllegalStateException(
            String.format(
                "Unable to find inbound timer receiver for instruction %s, transform %s, and timer family %s.",
                timers.getInstructionId(), timers.getTransformId(), timers.getTimerFamilyId()));
      }
      EndpointStatus<TimerEndpoint<?>> endpoint =
          timerFamilyIdToEndpoints.get(timers.getTimerFamilyId());
      if (endpoint == null) {
        throw new IllegalStateException(
            String.format(
                "Unable to find inbound timer receiver for instruction %s, transform %s, and timer family %s.",
                timers.getInstructionId(), timers.getTransformId(), timers.getTimerFamilyId()));
      } else if (endpoint.isDone) {
        throw new IllegalStateException(
            String.format(
                "Received timer after inbound timer receiver is done for instruction %s, transform %s, and timer family %s.",
                timers.getInstructionId(), timers.getTransformId(), timers.getTimerFamilyId()));
      }
      InputStream inputStream = timers.getTimers().newInput();
      Coder<Object> coder = (Coder<Object>) endpoint.endpoint.getCoder();
      FnDataReceiver<Object> receiver = (FnDataReceiver<Object>) endpoint.endpoint.getReceiver();
      while (inputStream.available() > 0) {
        receiver.accept(coder.decode(inputStream));
      }
      if (timers.getIsLast()) {
        endpoint.isDone = true;
        numEndpointsThatAreIncomplete -= 1;
      }
    }
    return numEndpointsThatAreIncomplete == 0;
  }

View on GitHub (pinned to 12126d8942)

Solutions

  1. Stop streaming timers for a family once its endpoint is done; check endpoint state before sending.
  2. Ensure isLast semantics for Timers halt the harness stream at the right point.
  3. Catch IllegalStateException in awaitCompletion and fail the bundle; look for version mismatches or races if it recurs.

Example fix

// before
timerReceiver.accept(timers); // may race with endpoint close
// after
if (!endpoint.isDone) {
  timerReceiver.accept(timers);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (endpoint.isDone) { /* stop streaming timers */ }

Try / catch

try { observer.awaitCompletion(); } catch (IllegalStateException e) { failBundle(instructionId, e); }

Prevention

When it happens

Trigger: Harness sends Elements.Timers after the timer endpoint completed — racing shutdown, duplicated isLast batches, or redelivery of timers after the bundle finished during awaitCompletion.

Common situations: Network buffering delays timer messages past bundle completion; harness keeps streaming after isLast; runner aborts the bundle while timers are in flight.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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