aeron-io/aeron · error · InvalidChannelException
term-offset= must be a multiple of FRAME_ALIGNMENT: channel=
Error message
term-offset={termOffset} must be a multiple of FRAME_ALIGNMENT: channel={channelUri} What it means
Term offsets mark the start of protocol frames, so the term-offset URI parameter must be a multiple of FRAME_ALIGNMENT (32 bytes). Unaligned offsets would corrupt the log buffer framing and are rejected.
Solutions
- Round the offset down/up to a multiple of 32 using BitUtil.align or FrameDescriptor.isFrameAligned
- Remove the term-offset param if exact positioning is not required
- Compute the offset from a position as position & (termLength - 1), which is frame-aligned for aligned term lengths
Example fix
// before "aeron:udp?endpoint=...:40456|term-offset=100" // after "aeron:udp?endpoint=...:40456|term-offset=128"
Defensive patterns
Strategy: validation
Validate before calling
if (termOffset % FrameAlignment.FRAME_ALIGNMENT != 0) throw new IllegalArgumentException("term-offset must be frame-aligned"); Try / catch
try { pub = aeron.addPublication(uri, streamId); } catch (InvalidChannelException e) { log.error("unaligned term-offset: {}", e.getMessage()); } Prevention
- Use BitUtil.align(offset, FRAME_ALIGNMENT) before building URIs
- Derive offsets from positions rather than raw byte counts
- Add an isFrameAligned assertion in URI-building helpers
When it happens
Trigger: A channel URI with a term-offset that is not a multiple of 32 (e.g. term-offset=100) when Aeron.addPublication resolves publication params.
Common situations: Deriving offsets by manual arithmetic without aligning; carrying over raw byte positions from a dump; typos in a hand-built URI.
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
- difference greater than 2^31 - 1: initial-term-id=
- invalid prefix
- params must be used as a complete set: initial-term-id…
- stream-id= does not match provided streamId=
- term-offset= out of range: channel=
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/3d4811ccd572b86e.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-driver/src/main/java/io/aeron/driver/PublicationParams.java:141
params.termId = parseInt(termIdStr, TERM_ID_PARAM_NAME);
params.termOffset = parseInt(termOffsetStr, TERM_OFFSET_PARAM_NAME);
if (params.termOffset > params.termLength)
{
throw new InvalidChannelException(
TERM_OFFSET_PARAM_NAME + "=" + params.termOffset + " > " +
TERM_LENGTH_PARAM_NAME + "=" + params.termLength + ": channel=" + channelUri);
}
if (params.termOffset < 0 || params.termOffset > LogBufferDescriptor.TERM_MAX_LENGTH)
{
throw new InvalidChannelException(
TERM_OFFSET_PARAM_NAME + "=" + params.termOffset + " out of range: channel=" + channelUri);
}
if (!FrameDescriptor.isFrameAligned(params.termOffset))
{
throw new InvalidChannelException(
TERM_OFFSET_PARAM_NAME + "=" + params.termOffset +
" must be a multiple of FRAME_ALIGNMENT: channel=" + channelUri);
}
if (params.termId - params.initialTermId < 0)
{
throw new InvalidChannelException(
"difference greater than 2^31 - 1: " + INITIAL_TERM_ID_PARAM_NAME + "=" +
params.initialTermId + " when " + TERM_ID_PARAM_NAME + "=" + params.termId + " channel=" +
channelUri);
}
params.hasPosition = true;
}
else
{
params.initialTermId = BitUtil.generateRandomisedId();
params.termId = params.initialTermId;View on GitHub (pinned to 6d60124e15)