aeron-io/aeron · error · ConfigurationException
Channel media type mismatch. When using…
Error message
Channel media type mismatch. When using `control-mode=response`, the `replayChannel` media type must match the media type for the archive control channel.
What it means
When the replayChannel URI includes control-mode=response, the replay channel doubles as an archive control-response channel. conclude() compares its media type (IPC vs network) against the archive control request channel; a mismatch (e.g. replay over UDP while archive control uses IPC) would make response subscriptions unusable, so a ConfigurationException is thrown.
Solutions
- Make the replayChannel transport match the archive control channel: if controlRequestChannel is udp, use aeron:udp in replayChannel (and vice versa).
- Remove control-mode=response from the replayChannel if you do not need the replay stream to carry archive control responses.
- Align aeronArchiveContext.controlRequestChannel() with your intended transport so both sides agree.
Example fix
// before
archiveCtx.controlRequestChannel("aeron:udp?endpoint=localhost:8010");
ctx.replayChannel("aeron:ipc?control-mode=response"); // ipc vs udp mismatch
ctx.conclude(); // throws: Channel media type mismatch
// after
archiveCtx.controlRequestChannel("aeron:udp?endpoint=localhost:8010");
ctx.replayChannel("aeron:udp?endpoint=localhost:10001|control-mode=response"); Defensive patterns
Strategy: validation
Validate before calling
ChannelUri replayUri = ChannelUri.parse(replayChannel);
if (replayUri.hasControlModeResponse() &&
replayUri.isIpc() != ChannelUri(archiveCtx.controlRequestChannel()).isIpc()) {
throw new IllegalArgumentException("replayChannel transport must match archive control channel when control-mode=response");
} Try / catch
try {
ctx.conclude();
} catch (ConfigurationException e) {
// rebuild replayChannel URI with matching transport
} Prevention
- Derive the replayChannel transport from the archive control channel rather than hardcoding ipc or udp.
- Only add control-mode=response when the replay stream must serve as a control-response channel.
When it happens
Trigger: Setting replayChannel to a URI containing '|control-mode=response' whose transport (ipc vs udp/tcp) differs from aeronArchiveContext.controlRequestChannel(). E.g. replayChannel="aeron:ipc?control-mode=response" while archive control is aeron:udp?..., or vice versa.
Common situations: Copying a shared-memory (ipc) archive config into a network deployment (or the reverse); manually adding control-mode=response for streaming-connection replay but on a different transport; container/host boundary changes the archive control channel default.
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
- aeronArchiveContext must be set
- Archive.Context.controlChannel must be set
- Archive.Context.controlChannel must be UDP media: uri=
- Archive.Context.recordingEventsChannel must be set if…
- Archive.Context.replicationChannel must be set
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/d504cd88ec1ff697.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-archive/src/main/java/io/aeron/archive/client/PersistentSubscription.java:1734
{
throw new ConfigurationException("invalid recordingId " + recordingId);
}
if (FROM_LIVE > startPosition)
{
throw new ConfigurationException("invalid startPosition " + startPosition);
}
final ChannelUri replayChannelUri = ChannelUri.parse(replayChannel);
if (replayChannelUri.hasControlModeResponse())
{
final String controlRequestChannel = aeronArchiveContext.controlRequestChannel();
if (null != controlRequestChannel &&
!replayChannelUri.isIpc() == ChannelUri.parse(controlRequestChannel).isIpc()
)
{
throw new ConfigurationException(
"Channel media type mismatch. " +
"When using `control-mode=response`, the `replayChannel` media type must match the media" +
" type for the archive control channel."
);
}
}
replayChannelUri.put(CommonContext.REJOIN_PARAM_NAME, "false");
replayChannel = replayChannelUri.toString();
if (null == aeron)
{
final Aeron.Context aeronCtx = new Aeron.Context()
.clientName("PersistentSubscription")
.subscriberErrorHandler(RethrowingErrorHandler.INSTANCE)
.useConductorAgentInvoker(true);
if (null != aeronDirectoryName)View on GitHub (pinned to 6d60124e15)