aeron-io/aeron · error · IllegalArgumentException

Wildcard port specified on resolvedEndpoint=

Error message

Wildcard port specified on resolvedEndpoint=<resolvedEndpoint>

What it means

replaceEndpointWildcardPort() exists to replace a wildcard port (endpoint ending in ':0') with the actually bound port. If the resolvedEndpoint itself still has wildcard port ':0', there is nothing concrete to substitute, so it throws IllegalArgumentException.

Solutions

  1. Pass the actual resolved local address of the bound channel (e.g. from publication localSocketAddresses / subscription LocalSocketAddress), not the wildcard config
  2. Check with endsWith(":0") before calling and skip or fail fast with a clear message
  3. Ensure the transport has fully bound before reading the resolved endpoint

Example fix

// before
publication.replaceEndpointWildcardPort("localhost:0"); // still wildcard
// after
String resolved = publication.localSocketAddresses()[0].getHostString() + ":" +
    publication.localSocketAddresses()[0].getPort();
publication.replaceEndpointWildcardPort(resolved);
Defensive patterns

Strategy: validation

Validate before calling

static void requireNonWildcard(String resolvedEndpoint) {
    if (resolvedEndpoint == null || resolvedEndpoint.endsWith(":0")) {
        throw new IllegalArgumentException("resolvedEndpoint must have a concrete port: " + resolvedEndpoint);
    }
}

Type guard

static boolean isConcretePort(String endpoint) {
    int i = endpoint == null ? -1 : endpoint.lastIndexOf(':');
    return i > 0 && !endpoint.substring(i + 1).equals("0");
}

Try / catch

try {
    channelUri.replaceEndpointWildcardPort(resolvedEndpoint);
} catch (IllegalArgumentException e) {
    log.error("Wildcard port not resolved: {}", resolvedEndpoint, e);
    throw new IllegalStateException("Endpoint was not resolved before substitution", e);
}

Prevention

When it happens

Trigger: Calling replaceEndpointWildcardPort() with a resolvedEndpoint ending in ":0", e.g. "localhost:0" — typically because the caller passed the original (unresolved) channel endpoint instead of the resolved local socket address.

Common situations: Reusing the publication's original URI endpoint rather than the locally bound address from LocalSocketAddress; passing a not-yet-resolved wildcard configuration through by mistake.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/ChannelUri.java:622

     * Uses the supplied endpoint to resolve any wildcard ports. If the existing endpoint has a value of "0" for then
     * the port of this endpoint will be used instead. If the endpoint is not specified in this uri, then the whole
     * supplied endpoint is used. If the endpoint exists and has a non-wildcard port, then the existing endpoint is
     * retained.
     *
     * @param resolvedEndpoint The endpoint to supply a resolved endpoint port.
     * @throws IllegalArgumentException if the supplied resolvedEndpoint does not have a port or the port is zero.
     * @throws NullPointerException     if the supplied resolvedEndpoint is null
     */
    public void replaceEndpointWildcardPort(final String resolvedEndpoint)
    {
        final int portSeparatorIndex = requireNonNull(resolvedEndpoint, "resolvedEndpoint is null").lastIndexOf(':');
        if (-1 == portSeparatorIndex)
        {
            throw new IllegalArgumentException("No port specified on resolvedEndpoint=" + resolvedEndpoint);
        }
        if (resolvedEndpoint.endsWith(":0"))
        {
            throw new IllegalArgumentException("Wildcard port specified on resolvedEndpoint=" + resolvedEndpoint);
        }

        final String existingEndpoint = get(ENDPOINT_PARAM_NAME);
        if (null == existingEndpoint)
        {
            put(ENDPOINT_PARAM_NAME, resolvedEndpoint);
        }
        else if (existingEndpoint.endsWith(":0"))
        {
            final String endpoint = existingEndpoint.substring(0, existingEndpoint.length() - 2) +
                resolvedEndpoint.substring(resolvedEndpoint.lastIndexOf(':'));
            put(ENDPOINT_PARAM_NAME, endpoint);
        }
    }

    /**
     * Call consumer for each parameter defined in the URI.
     *

View on GitHub (pinned to 6d60124e15)