aeron-io/aeron · error · InvalidChannelException
option conflicts with existing subscription
Error message
option conflicts with existing subscription: ${CHANNEL_SEND_TIMESTAMP_OFFSET_PARAM_NAME}=${offset} existingChannel=${existingChannel} channel=${channel} What it means
When a new subscription reuses an existing SendChannelEndpoint (same channel), the driver requires the channel-send-timestamp-offset option to match exactly what the existing endpoint was created with. A mismatch would make timestamps inconsistent across subscriptions sharing the endpoint, so the driver throws InvalidChannelException naming both the existing channel URI and the new one.
Solutions
- Make all subscriptions on the same channel use the identical channel-send-timestamp-offset param value
- Set the option explicitly on every channel string rather than relying on defaults so all agree
- Use distinct channels/endpoints if different timestamp behavior per subscription is truly required
- Audit all channel strings deployed in the process for the conflicting parameter
Example fix
// before
aeron.addSubscription("aeron:udp?endpoint=224.0.1.1:40456", streamId); // offset default
aeron.addSubscription("aeron:udp?endpoint=224.0.1.1:40456|channel-send-timestamp-offset=0", streamId); // conflicts
// after
String ch = "aeron:udp?endpoint=224.0.1.1:40456|channel-send-timestamp-offset=0";
aeron.addSubscription(ch, streamId);
aeron.addSubscription(ch, streamId); // identical options Defensive patterns
Strategy: validation
Validate before calling
ChannelUri uri = ChannelUri.parse(channel);
String offset = uri.get(CHANNEL_SEND_TIMESTAMP_OFFSET_PARAM_NAME); // compare with the value used by existing subscriptions on this endpoint
if (existingOffset != null && !Objects.equals(existingOffset, offset))
{
throw new IllegalArgumentException("channel-send-timestamp-offset conflicts with existing subscription");
} Try / catch
try
{
aeron.addSubscription(channel, streamId);
}
catch (InvalidChannelException ex)
{
if (ex.getMessage().contains(CHANNEL_SEND_TIMESTAMP_OFFSET_PARAM_NAME))
{
log.error("Timestamp offset option conflicts with an existing subscription on this channel");
}
} Prevention
- Centralize channel URI construction so all subscriptions on a channel share identical params
- Never rely on default option values when sharing channels; set options explicitly
- Document required channel params for all in-process components sharing a driver
When it happens
Trigger: Adding a second subscription on the same UDP channel URI but with a different channel-send-timestamp-offset param value (or one with the option and one without, given differing defaults) than the existing subscription's endpoint.
Common situations: Two services/libraries in one process subscribing to the same channel but configured independently (one sets timestamps offset to media driver default, the other leaves it unset); config drift after upgrading where defaults changed; copying channel strings between environments.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- option conflicts with existing subscription
- option conflicts with existing subscription: reliable=
- option conflicts with existing subscription: rejoin=
- option conflicts with existing subscription: isResponse=
- Aeron client instance must set…
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/43ada0948b79ab74.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-driver/src/main/java/io/aeron/driver/DriverConductor.java:1523
SOCKET_RCVBUF_PARAM_NAME,
udpChannel.socketRcvbufLength(),
channelEndpoint.socketRcvbufLength(),
udpChannel.originalUriString(),
channelEndpoint.originalUriString());
validateChannelBufferLength(
SOCKET_SNDBUF_PARAM_NAME,
udpChannel.socketSndbufLength(),
channelEndpoint.socketSndbufLength(),
udpChannel.originalUriString(),
channelEndpoint.originalUriString());
}
private static void validateChannelSendTimestampOffset(
final UdpChannel udpChannel, final SendChannelEndpoint channelEndpoint)
{
if (udpChannel.channelSendTimestampOffset() != channelEndpoint.udpChannel().channelSendTimestampOffset())
{
throw new InvalidChannelException(
"option conflicts with existing subscription: " + CHANNEL_SEND_TIMESTAMP_OFFSET_PARAM_NAME + "=" +
udpChannel.channelSendTimestampOffset() +
" existingChannel=" + channelEndpoint.originalUriString() + " channel=" +
udpChannel.originalUriString());
}
}
private static void validateReceiveTimestampOffset(
final UdpChannel udpChannel, final ReceiveChannelEndpoint channelEndpoint)
{
if (udpChannel.channelReceiveTimestampOffset() !=
channelEndpoint.subscriptionUdpChannel().channelReceiveTimestampOffset())
{
throw new InvalidChannelException(
"option conflicts with existing subscription: " + CHANNEL_RECEIVE_TIMESTAMP_OFFSET_PARAM_NAME + "=" +
udpChannel.channelReceiveTimestampOffset() +
" existingChannel=" + channelEndpoint.originalUriString() + " channel=" +
udpChannel.originalUriString());View on GitHub (pinned to 6d60124e15)