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 control operation (add/remove destination) is performed on a send channel endpoint whose multiSndDestination is not a ManualSndMultiDestination. Only publication channels created with control-mode=manual allow dynamic destination management.

Solutions

  1. Create the publication channel URI with control-mode=manual, e.g. aeron:udp?control-mode=manual
  2. Ensure all publications on the same channel/stream use consistent control mode so endpoint lookup finds a manual-capable endpoint
  3. Catch ControlProtocolException and inspect getErrorCode() == ErrorCode.INVALID_CHANNEL to detect the misconfiguration

Example fix

// before
Publication pub = aeron.addPublication("aeron:udp?endpoint=224.0.1.1:40456", 1001);
pub.addDestination("aeron:udp?endpoint=10.0.0.1:40456"); // throws
// after
Publication pub = aeron.addPublication("aeron:udp?control-mode=manual", 1001);
pub.addDestination("aeron:udp?endpoint=10.0.0.1:40456");
Defensive patterns

Strategy: try-catch

Validate before calling

boolean manual = uri.contains("control-mode=manual");
if (!manual) throw new IllegalStateException("send channel must use control-mode=manual for addDestination");

Try / catch

try {
    publication.addDestination(dstUri);
} catch (ControlProtocolException e) {
    if (e.errorCode() == ErrorCode.INVALID_CHANNEL) { /* recreate publication with control-mode=manual */ }
}

Prevention

When it happens

Trigger: validateAllowsManualControl is invoked from findExistingManualSendChannelEndpoint when reusing/looking up a send channel for a manual-control request, and the existing endpoint was created from a URI without control-mode=manual.

Common situations: Calling Publication.addDestination/removeDestination on a publication created from a normal aeron:udp?endpoint=... URI; an existing publication on the same stream/URI was created without manual mode so the endpoint reuse fails; MDC publishing configured incorrectly.

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


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

Appendix: source

Thrown at aeron-driver/src/main/java/io/aeron/driver/media/SendChannelEndpoint.java:570

        {
            final long responseCorrelationId = publication.responseCorrelationId();
            if (Aeron.NULL_VALUE != responseCorrelationId)
            {
                conductorProxy.responseSetup(responseCorrelationId, msg.responseSessionId());
            }
        }
    }

    /**
     * Validate that the channel allows manual control for destinations.
     * <p>
     * If not then a {@link ControlProtocolException} will be thrown.
     */
    public void validateAllowsManualControl()
    {
        if (!(multiSndDestination instanceof ManualSndMultiDestination))
        {
            throw new ControlProtocolException(ErrorCode.INVALID_CHANNEL, "channel does not allow manual control");
        }
    }

    /**
     * Add a destination for an MDC channel.
     *
     * @param channelUri     for the destination to be added.
     * @param address        of the destination to be added.
     * @param registrationId of the destination.
     */
    public void addDestination(final ChannelUri channelUri, final InetSocketAddress address, final long registrationId)
    {
        multiSndDestination.addDestination(channelUri, address, registrationId);
    }

    /**
     * Remove a destination from an MDC channel.
     *

View on GitHub (pinned to 6d60124e15)