aeron-io/aeron · error · IllegalArgumentException
termOffset= must be a multiple of FRAME_ALIGNMENT: channel=
Error message
termOffset=<termOffset> must be a multiple of FRAME_ALIGNMENT: channel=<channelUri>
What it means
Aeron data frames are aligned to FRAME_ALIGNMENT (32 bytes); a subscription's explicit term-offset must be frame-aligned so the subscriber can start on a frame boundary. Unaligned offsets are rejected with IllegalArgumentException.
Solutions
- Round the offset down to a multiple of 32: termOffset &= ~(FrameDescriptor.FRAME_ALIGNMENT - 1).
- Record offsets programmatically (e.g. from image.position()) so they are always aligned.
- Use a power-of-two-friendly computation like position & (termLength - 1) then align.
Example fix
// before int termOffset = recordedPosition % termLength; // may be unaligned // after int termOffset = (int)(recordedPosition & (termLength - 1)) & ~(FrameDescriptor.FRAME_ALIGNMENT - 1);
Defensive patterns
Strategy: validation
Validate before calling
termOffset &= ~(FrameDescriptor.FRAME_ALIGNMENT - 1); // align down to 32 bytes before building the URI
Prevention
- Always align offsets to FRAME_ALIGNMENT (32) before use.
- Record resume positions programmatically rather than by hand.
When it happens
Trigger: Subscription URI with term-offset not a multiple of 32, e.g. term-offset=33 or term-offset=100.
Common situations: Deriving the offset from arbitrary positions recorded by hand; computing offsets with non-power-of-two arithmetic; typos in recorded values.
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
- params must be used as a complete set: initialTermId termId…
- termOffset= out of range: channel=
- difference greater than 2^31 - 1: initialTermId=
- invalid position
- empty key not allowed at index
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/5b6444a2cb7fe87a.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-driver/src/main/java/io/aeron/driver/SubscriptionParams.java:97
throw new IllegalArgumentException("params must be used as a complete set: " +
INITIAL_TERM_ID_PARAM_NAME + " " +
TERM_ID_PARAM_NAME + " " +
TERM_OFFSET_PARAM_NAME + " channel=" + channelUri);
}
params.initialTermId = Integer.parseInt(initialTermIdStr);
params.termId = Integer.parseInt(termIdStr);
params.termOffset = Integer.parseInt(termOffsetStr);
if (params.termOffset < 0 || params.termOffset > LogBufferDescriptor.TERM_MAX_LENGTH)
{
throw new IllegalArgumentException(
TERM_OFFSET_PARAM_NAME + "=" + params.termOffset + " out of range: channel=" + channelUri);
}
if (!FrameDescriptor.isFrameAligned(params.termOffset))
{
throw new IllegalArgumentException(
TERM_OFFSET_PARAM_NAME + "=" + params.termOffset +
" must be a multiple of FRAME_ALIGNMENT: channel=" + channelUri);
}
if (params.termId - params.initialTermId < 0)
{
throw new IllegalStateException(
"difference greater than 2^31 - 1: " + INITIAL_TERM_ID_PARAM_NAME + "=" +
params.initialTermId + " when " + TERM_ID_PARAM_NAME + "=" + params.termId + " channel=" +
channelUri);
}
params.hasJoinPosition = true;
}
final String reliableStr = channelUri.get(RELIABLE_STREAM_PARAM_NAME);
params.isReliable = null != reliableStr ? "true".equals(reliableStr) : context.reliableStream();
View on GitHub (pinned to 6d60124e15)