aeron-io/aeron · error · IllegalStateException
difference greater than 2^31 - 1: initialTermId=
Error message
difference greater than 2^31 - 1: initialTermId=<initialTermId> when termId=<termId> channel=<channelUri>
What it means
The driver derives the join position from initialTermId and termId; if termId - initialTermId is negative the implied difference exceeds 2^31 - 1 and cannot be represented, so an IllegalStateException is thrown. This catches wrap-around arithmetic mistakes in the supplied position params.
Solutions
- Ensure termId >= initialTermId (within int arithmetic) for the position you want.
- Account for term wrap-around explicitly when computing ids from a position: termId = initialTermId + (int)(position / termLength).
- Recompute all three params together from a recorded position rather than editing one in isolation.
Example fix
// before uri += "|initial-term-id=" + initialTermId + "|term-id=" + currentTermId; // currentTermId wrapped below initialTermId // after int termId = initialTermId + (int)(position / termLength); uri += "|initial-term-id=" + initialTermId + "|term-id=" + termId + "|term-offset=" + termOffset;
Defensive patterns
Strategy: validation
Validate before calling
if (termId - initialTermId < 0) {
throw new IllegalArgumentException("termId must be >= initialTermId (within 2^31 - 1)");
} Prevention
- Compute termId = initialTermId + (int)(position / termLength) so wrap is handled.
- Never hand-edit one of the three position params in isolation.
When it happens
Trigger: Subscription URI where termId is numerically less than initialTermId without a valid wrap, e.g. initial-term-id=100|term-id=50.
Common situations: Recomputing term ids after wrap incorrectly; mixing term ids recorded from different streams; hand-editing initial-term-id upward while leaving term-id stale.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- params must be used as a complete set: initialTermId termId…
- termOffset= out of range: channel=
- termOffset= must be a multiple of FRAME_ALIGNMENT: channel=
- empty key not allowed at index
- invalid end of key at index
AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12).
Data as JSON: /api/errors/254e93a3eafd37fc.
Report an issue: GitHub.
Appendix: source
Thrown at aeron-driver/src/main/java/io/aeron/driver/SubscriptionParams.java:104
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();
final String rejoinStr = channelUri.get(REJOIN_PARAM_NAME);
params.isRejoin = null != rejoinStr ? "true".equals(rejoinStr) : context.rejoinStream();
final String tetherStr = channelUri.get(TETHER_PARAM_NAME);
params.isTether = null != tetherStr ? "true".equals(tetherStr) : context.tetherSubscriptions();
final String sparseStr = channelUri.get(SPARSE_PARAM_NAME);View on GitHub (pinned to 6d60124e15)