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
- Stop streaming timers for a family once its endpoint is done; check endpoint state before sending.
- Ensure isLast semantics for Timers halt the harness stream at the right point.
- 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
- Stop streaming timers once the family endpoint is done
- Honor Timers isLast semantics
- Handle shutdown races by failing the bundle cleanly
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
- Received data after inbound data receiver is done for instru
- Unable to find inbound timer receiver for instruction %s, tr
- Instruction id was poisoned
- Unregistering consumer which was not registered.
- PoisonedException
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/66779afd89009cc5.
Report an issue: GitHub.