apache/beam · error · IllegalStateException
Outbound data endpoint already registered for
Error message
Outbound data endpoint already registered for
What it means
BeamFnDataOutboundAggregator registers one outbound logical data endpoint per pTransformId per bundle. This IllegalStateException is thrown when registerOutputDataLocation is called with a pTransformId that already has a registered data receiver, preventing duplicate endpoint registration which would corrupt the bundle's output mapping.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/fn/data/BeamFnDataOutboundAggregator.java:143
public void start() {
if (timeLimit > 0 && this.flushFuture == null) {
this.flushFuture =
Executors.newSingleThreadScheduledExecutor(
new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("DataBufferOutboundFlusher-thread")
.build())
.scheduleAtFixedRate(this::flush, timeLimit, timeLimit, TimeUnit.MILLISECONDS);
}
}
/**
* Register the outbound data logical endpoint, returns the FnDataReceiver for processing the
* endpoint's outbound data.
*/
public <T> FnDataReceiver<T> registerOutputDataLocation(String pTransformId, Coder<T> coder) {
if (outputDataReceivers.containsKey(pTransformId)) {
throw new IllegalStateException(
"Outbound data endpoint already registered for " + pTransformId);
}
Receiver<T> receiver = new Receiver<>(coder);
if (timeLimit > 0) {
outputDataReceivers.put(pTransformId, receiver);
return data -> {
checkFlushThreadException();
synchronized (flushLock) {
receiver.accept(data);
}
};
}
outputDataReceivers.put(pTransformId, receiver);
return receiver;
}
/**
* Register the outbound timers logical endpoint, returns the FnDataReceiver for processing theView on GitHub (pinned to 12126d8942)
Solutions
- Ensure registerOutputDataLocation is called at most once per pTransformId per bundle; check existing registrations before calling
- Check that the wiring code (addOutgoingDataEndpoint, registerOutputLocation, newBundle) is not invoked redundantly
- Upgrade Beam — bundle lifecycle bugs in custom runners have been fixed in later versions
- Recreate/reset the aggregator between bundles so stale registrations are cleared
Example fix
// before aggregator.registerOutputDataLocation(pTransformId, coder); aggregator.registerOutputDataLocation(pTransformId, coder); // throws // after // register exactly once per pTransformId per bundle
Defensive patterns
Strategy: validation
Validate before calling
if (registeredTransformIds.contains(pTransformId)) {
throw new IllegalArgumentException("duplicate data endpoint " + pTransformId);
}
registeredTransformIds.add(pTransformId); Try / catch
try {
aggregator.registerOutputDataLocation(pTransformId, coder);
} catch (IllegalStateException e) {
LOG.warn("endpoint already registered: " + pTransformId, e);
} Prevention
- Register each pTransformId exactly once per bundle
- Centralize endpoint registration in newBundle/setup, not per-element code
- Track registered ids in a Set during bundle setup
When it happens
Trigger: Calling registerOutputDataLocation twice with the same pTransformId within one bundle; transform/receiver wiring (e.g. via addOutgoingDataEndpoint or fnDataReceiver) registering the same output location twice.
Common situations: Runner/SDK harness bugs where bundle setup runs the registration path twice (a PTransform re-initialized mid-bundle); custom runner code calling registerOutputLocation without clearing prior state between bundles.
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
- Outbound timers endpoint already registered for ${timerKey}
- Conflicting registrations for: %s
- typehint for arg type %s already exists
- Cannot access state in non-window observing context.
- State stream is closed.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/4885af60bfd71ff3.
Report an issue: GitHub.