aeron-io/aeron · error · ControlProtocolException
INVALID_CHANNEL
INVALID_CHANNEL
Error message
channel does not allow manual control
What it means
Aeron throws ControlProtocolException(ErrorCode.INVALID_CHANNEL) when a manual (MDC) control operation such as adding/removing destinations is requested on a receive channel endpoint that is not configured as a multi-destination (no MultiRcvDestination). Only channels created with control-mode=manual support dynamic destination control.
Solutions
- Create the subscription channel with control-mode=manual in the URI, e.g. aeron:udp?control-mode=manual
- Restructure code so destination add/remove calls are only made on subscriptions created for manual multi-destination control
- Catch ControlProtocolException and check getErrorCode() == ErrorCode.INVALID_CHANNEL to surface the misconfigured channel
Example fix
// before
Subscription sub = aeron.addSubscription("aeron:udp?endpoint=127.0.0.1:40456", 1001);
sub.addDestination("aeron:udp?endpoint=127.0.0.1:40457"); // throws
// after
Subscription sub = aeron.addSubscription("aeron:udp?control-mode=manual", 1001);
sub.addDestination("aeron:udp?endpoint=127.0.0.1:40457"); Defensive patterns
Strategy: try-catch
Validate before calling
boolean manual = uri.contains("control-mode=manual");
if (!manual) throw new IllegalStateException("receive channel must use control-mode=manual for addDestination"); Try / catch
try {
subscription.addDestination(dstUri);
} catch (ControlProtocolException e) {
if (e.errorCode() == ErrorCode.INVALID_CHANNEL) { /* recreate subscription with control-mode=manual */ }
} Prevention
- Always create MDC receive channels with control-mode=manual
- Centralize channel URI construction in one helper that enforces the mode
- Only call addDestination/removeDestination on subscriptions you created as manual
When it happens
Trigger: Driver command ADD_RCV_DESTINATION/REMOVE_RCV_DESTINATION arrives for a subscription whose ReceiveChannelEndpoint was created from a plain (non-manual) URI, so validateAllowsDestinationControl finds multiRcvDestination == null.
Common situations: Calling Subscription.addDestination (or driver client addRcvDestination) on a subscription created from a normal aeron:udp?endpoint=... URI instead of one with control-mode=manual; mixing manual and non-manual channels in MDC setups.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- INVALID_CHANNEL
- explicit control expected with dynamic control mode:
- URIs for UDP must specify an endpoint, control, tags, or…
- Aeron client instance must set…
- Aeron client must use a RethrowingErrorHandler
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/ab5a9bc1dc06c4ae.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-driver/src/main/java/io/aeron/driver/media/ReceiveChannelEndpoint.java:505
* Has the channel got control of destinations for MDS.
*
* @return true if the channel got control of destinations for MDS.
*/
public boolean hasDestinationControl()
{
return null != multiRcvDestination;
}
/**
* Validate that the channel allows destination control.
* <p>
* If not then a {@link ControlProtocolException} will be thrown.
*/
public void validateAllowsDestinationControl()
{
if (null == multiRcvDestination)
{
throw new ControlProtocolException(ErrorCode.INVALID_CHANNEL, "channel does not allow manual control");
}
}
/**
* Is the primary transport multicast?
*
* @return true if the primary transport is multicast.
*/
public boolean isMulticast()
{
return isMulticast(0);
}
/**
* Is a given transport index multicast?
*
* @param transportIndex to check for multicast.
* @return true if the transport index is multicast.View on GitHub (pinned to 6d60124e15)