aeron-io/aeron · error · IllegalArgumentException

either 'endpoint' or 'control' must be specified for UDP.

Error message

either 'endpoint' or 'control' must be specified for UDP.

What it means

For UDP channels, validate() requires a routing destination: either a unicast/multicast endpoint or a control (multicast) endpoint must be set. A UDP media with both endpoint and controlEndpoint null has nowhere to send, so IllegalArgumentException is thrown.

Solutions

  1. Add .endpoint("host:port") (or .control(multicastAddress:port)) to the builder for UDP channels
  2. Verify the config actually contains the endpoint or control value and that the key name matches
  3. If the channel is genuinely local-only, use media "ipc" instead of udp

Example fix

// before
new ChannelUriStringBuilder().media(CommonContext.UDP_MEDIA).validate();
// after
new ChannelUriStringBuilder()
    .media(CommonContext.UDP_MEDIA)
    .endpoint("localhost:40456")
    .validate();
Defensive patterns

Strategy: validation

Validate before calling

static void requireUdpDestination(String media, String endpoint, String control) {
    if ("udp".equals(media) && endpoint == null && control == null) {
        throw new IllegalArgumentException("udp channel requires 'endpoint' or 'control'");
    }
}

Type guard

static boolean hasUdpDestination(ChannelUriStringBuilder b) {
    try { b.validate(); return true; } catch (IllegalArgumentException e) { return false; }
}

Try / catch

try {
    String uri = builder.validate().build();
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("either 'endpoint' or 'control'")) {
        throw new IllegalArgumentException("UDP channel config must set endpoint or control", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Builder with media("udp") but neither .endpoint(...) nor .control(...) called, then validate()/build(). IPC channels are exempt from this check.

Common situations: Reusing a builder configured for IPC with UDP media; config file that specifies transport=udp but omits endpoint/control keys; code paths that assume a default endpoint exists.

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/7ffa085aa2543929. Report an issue: GitHub.

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/ChannelUriStringBuilder.java:221

        return this;
    }

    /**
     * Validates that the collection of set parameters are valid together.
     *
     * @return this for a fluent API.
     * @throws IllegalArgumentException if the combination of params is invalid.
     */
    public ChannelUriStringBuilder validate()
    {
        if (null == media)
        {
            throw new IllegalArgumentException("media type is mandatory");
        }

        if (CommonContext.UDP_MEDIA.equals(media) && (null == endpoint && null == controlEndpoint))
        {
            throw new IllegalArgumentException("either 'endpoint' or 'control' must be specified for UDP.");
        }

        final boolean anyNonNull = null != initialTermId || null != termId || null != termOffset;
        final boolean anyNull = null == initialTermId || null == termId || null == termOffset;
        if (anyNonNull)
        {
            if (anyNull)
            {
                throw new IllegalArgumentException(
                    "either all or none of the parameters ['initialTermId', 'termId', 'termOffset'] must be provided");
            }

            if (termId - initialTermId < 0)
            {
                throw new IllegalArgumentException(
                    "difference greater than 2^31 - 1: termId=" + termId + " - initialTermId=" + initialTermId);
            }

View on GitHub (pinned to 6d60124e15)