aeron-io/aeron · error · IllegalArgumentException

explicit control expected with dynamic control mode:

Error message

explicit control expected with dynamic control mode: 

What it means

UdpChannel.parse throws IllegalArgumentException when a channel URI sets control-mode=dynamic but provides no explicit control address. Dynamic multi-destination-cast requires a known control address for the receiver(s) to contact, so an explicitly configured control is mandatory in that mode.

Solutions

  1. Add an explicit control address to the URI, e.g. aeron:udp?control-mode=dynamic|control=224.0.1.1:40456
  2. Confirm the parameter name is exactly 'control' and the value parses as address:port (or [v6]:port)
  3. If destinations are added manually at runtime, use control-mode=manual instead of dynamic

Example fix

// before
"aeron:udp?control-mode=dynamic"
// after
"aeron:udp?control-mode=dynamic|control=224.0.1.1:40456"
Defensive patterns

Strategy: validation

Validate before calling

boolean isDynamic = "dynamic".equals(params.get("control-mode"));
boolean hasControl = params.containsKey("control") && !params.get("control").isEmpty();
if (isDynamic && !hasControl) throw new IllegalArgumentException("control-mode=dynamic requires control=<address:port>");

Try / catch

try {
    UdpChannel.parse(uri, true, NameResolver.NULL_NAME_RESOLVER);
} catch (IllegalArgumentException e) {
    // reject/mend URI before configuring driver
}

Prevention

When it happens

Trigger: Parsing a URI such as aeron:udp?control-mode=dynamic (with no control= parameter) when creating a publication or subscription via Aeron.addPublication/addSubscription.

Common situations: MDC setups where the control= parameter was dropped or misspelled (e.g. control-adress typo); confusing control-mode with manual mode; partially edited URIs when switching from manual to dynamic mode.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/f2a7195c092564d2. Report an issue: GitHub.

Appendix: source

Thrown at aeron-driver/src/main/java/io/aeron/driver/media/UdpChannel.java:168

            final String tagIdStr = channelUri.channelTag();
            final ControlMode controlMode = parseControlMode(channelUri);

            final int socketRcvbufLength = parseBufferLength(channelUri, SOCKET_RCVBUF_PARAM_NAME);
            final int socketSndbufLength = parseBufferLength(channelUri, SOCKET_SNDBUF_PARAM_NAME);
            final int receiverWindowLength = parseBufferLength(
                channelUri, RECEIVER_WINDOW_LENGTH_PARAM_NAME);

            final boolean requiresAdditionalSuffix = !isDestination &&
                (null == endpointAddress && null == controlAddress ||
                (null != endpointAddress && endpointAddress.getPort() == 0) ||
                (null != controlAddress && controlAddress.getPort() == 0));

            final boolean hasNoDistinguishingCharacteristic =
                null == endpointAddress && null == controlAddress && null == tagIdStr;

            if (ControlMode.DYNAMIC == controlMode && null == controlAddress)
            {
                throw new IllegalArgumentException(
                    "explicit control expected with dynamic control mode: " + channelUriString);
            }

            if (hasNoDistinguishingCharacteristic && ControlMode.MANUAL != controlMode &&
                ControlMode.RESPONSE != controlMode)
            {
                throw new IllegalArgumentException(
                    "URIs for UDP must specify an endpoint, control, tags, or control-mode=manual/response: " +
                    channelUriString);
            }

            if (null != endpointAddress && endpointAddress.isUnresolved())
            {
                throw new UnknownHostException("could not resolve endpoint address: " + endpointAddress);
            }

            if (null != controlAddress && controlAddress.isUnresolved())
            {

View on GitHub (pinned to 6d60124e15)