aeron-io/aeron · error · InvalidChannelException

Aeron spies are invalid as send destinations: channel=

Error message

Aeron spies are invalid as send destinations: channel={destinationUri}

What it means

An Aeron "spy" channel (URI prefixed with "aeron-spy:") is a virtual channel that taps traffic from an existing network publication via local shared memory. Spies can only be used for subscriptions; using one as a send/publication destination is invalid and rejected with InvalidChannelException.

Solutions

  1. Use a plain "aeron:udp?..." URI for send destinations instead of a spy prefix.
  2. Only use aeron-spy URIs with addSubscription() to locally tap an existing publication.
  3. Validate destination URIs in your code, rejecting any prefix other than "aeron:" for sends.

Example fix

// before
publication.addDestination("aeron-spy:udp?endpoint=localhost:40456");
// after
publication.addDestination("aeron:udp?endpoint=localhost:40456");
Defensive patterns

Strategy: validation

Validate before calling

ChannelUri uri = ChannelUri.parse(destination);
if ("aeron-spy".equals(uri.prefix())) throw new IllegalArgumentException("spy cannot be a send destination");

Type guard

boolean isSendableDestination(ChannelUri uri) {
  return !"aeron-spy".equals(uri.prefix());
}

Try / catch

try { publication.addDestination(destination); }
catch (InvalidChannelException e) { if (e.getMessage().contains("spies are invalid as send destinations")) { /* replace with aeron:udp URI */ } else throw e; }

Prevention

When it happens

Trigger: Adding a spy URI as a publication or send destination, e.g. ChannelUri with prefix "aeron-spy:" passed to addPublication(), addDestination(), or MDC manual destination lists.

Common situations: Confusing spy subscriptions with spy publications; building dynamic destination lists where a spy URI sneaks in; misunderstanding that spy is receive-only local tapping.

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

Appendix: source

Thrown at aeron-driver/src/main/java/io/aeron/driver/DriverConductor.java:2375

                udpChannel.originalUriString());
        }
    }

    private static void validateTimestampConfiguration(final UdpChannel udpChannel)
    {
        if (null != udpChannel.channelUri().get(MEDIA_RCV_TIMESTAMP_OFFSET_PARAM_NAME))
        {
            throw new InvalidChannelException(
                "Media timestamps '" + MEDIA_RCV_TIMESTAMP_OFFSET_PARAM_NAME +
                    "' are not supported in the Java driver: channel=" + udpChannel.originalUriString());
        }
    }

    private static void validateDestinationUri(final ChannelUri uri, final String destinationUri)
    {
        if (SPY_QUALIFIER.equals(uri.prefix()))
        {
            throw new InvalidChannelException("Aeron spies are invalid as send destinations: channel=" +
                destinationUri);
        }

        for (final String invalidKey : INVALID_DESTINATION_KEYS)
        {
            if (uri.containsKey(invalidKey))
            {
                throw new InvalidChannelException(
                    "destinations must not contain the key: " + invalidKey + " channel=" + destinationUri);
            }
        }

        if (Objects.equals(CONTROL_MODE_RESPONSE, uri.get(MDC_CONTROL_MODE_PARAM_NAME)))
        {
            throw new InvalidChannelException("destinations may not specify " +
                MDC_CONTROL_MODE_PARAM_NAME + "=" + CONTROL_MODE_RESPONSE);
        }
    }

View on GitHub (pinned to 6d60124e15)