aeron-io/aeron · error · IllegalStateException
MTU greater than SO_SNDBUF for channel: mtu=
Error message
MTU greater than SO_SNDBUF for channel: mtu=<mtuLength> so-sndbuf=<osDefaultSocketSndbufLength> (OS default) existingChannel=<existingChannel> channel=<channel>
What it means
Same rule as the explicit so-sndbuf case: when the channel does not specify so-sndbuf, Aeron compares the MTU against the OS default socket send buffer (osDefaultSocketSndbufLength) and throws IllegalStateException if MTU exceeds it. The '(OS default)' marker in the message indicates this branch.
Solutions
- Lower the mtu URI value to fit the OS default send buffer
- Increase the OS default: sysctl -w net.core.wmem_default=<value> (and persist in /etc/sysctl.conf)
- Add an explicit so-sndbuf to the channel URI at least equal to the MTU
- Verify with `cat /proc/sys/net/core/wmem_default` before choosing MTU
Example fix
// before "aeron:udp?endpoint=localhost:40456|mtu=8948" // OS default SNDBUF is 4096 // after (either) "aeron:udp?endpoint=localhost:40456|mtu=8948|so-sndbuf=16384" // or shell: sysctl -w net.core.wmem_default=16384
Defensive patterns
Strategy: validation
Validate before calling
long osDefault = Long.parseLong(
java.nio.file.Files.readString(java.nio.file.Path.of("/proc/sys/net/core/wmem_default")).trim());
if (mtu > osDefault && uriLacksParam("so-sndbuf")) throw new IllegalArgumentException("mtu exceeds OS default SNDBUF"); Try / catch
try { publication = aeron.addPublication(uri, streamId); }
catch (IllegalStateException e) {
if (e.getMessage().contains("(OS default)")) {
throw new ConfigurationException("Increase net.core.wmem_default or set so-sndbuf in the channel URI", e);
} throw e;
} Prevention
- Check net.core.wmem_default on deployment hosts before choosing MTU
- Set an explicit so-sndbuf so behavior is OS-independent
- Document required sysctls in deployment manifests
When it happens
Trigger: Adding a network publication with a large `mtu=` URI value while the channel has no `so-sndbuf` param and the OS default SNDBUF (net.core.wmem_default) is smaller than the MTU.
Common situations: Linux hosts with default wmem_default (~212992) are usually fine, but constrained containers/VMs or explicitly shrunk sysctl defaults break large-MTU configs; cloud instances with low defaults.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- MTU greater than SO_SNDBUF for channel: mtu=
- could not resolve control address:
- could not resolve endpoint address:
- either 'endpoint' or 'control' must be specified for UDP.
- Initial window greater than SO_RCVBUF for channel: rcv-wnd=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/6052119073012fb2.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-driver/src/main/java/io/aeron/driver/PublicationParams.java:391
static void validateMtuForSndbuf(
final PublicationParams params,
final int channelSocketSndbufLength,
final MediaDriver.Context ctx,
final String channel,
final String existingChannel)
{
if (0 != channelSocketSndbufLength && params.mtuLength > channelSocketSndbufLength)
{
throw new IllegalStateException(
"MTU greater than SO_SNDBUF for channel: mtu=" + params.mtuLength +
" so-sndbuf=" + channelSocketSndbufLength +
(null == existingChannel ? "" : (" existingChannel=" + existingChannel)) +
" channel=" + channel);
}
else if (0 == channelSocketSndbufLength && params.mtuLength > ctx.osDefaultSocketSndbufLength())
{
throw new IllegalStateException(
"MTU greater than SO_SNDBUF for channel: mtu=" + params.mtuLength +
" so-sndbuf=" + ctx.osDefaultSocketSndbufLength() + " (OS default)" +
(null == existingChannel ? "" : (" existingChannel=" + existingChannel)) +
" channel=" + channel);
}
}
private void getLingerTimeoutNs(final ChannelUri channelUri, final MediaDriver.Context ctx)
{
final String lingerParam = channelUri.get(LINGER_PARAM_NAME);
if (null != lingerParam)
{
lingerTimeoutNs = SystemUtil.parseDuration(LINGER_PARAM_NAME, lingerParam);
}
else
{
lingerTimeoutNs = ctx.publicationLingerTimeoutNs();
}View on GitHub (pinned to 6d60124e15)