aeron-io/aeron · error · IllegalArgumentException

term offset not multiple of FRAME_ALIGNMENT

Error message

term offset not multiple of FRAME_ALIGNMENT: ${termOffset}

What it means

ChannelUriStringBuilder.termOffset(Integer) requires the offset to be a multiple of FRAME_ALIGNMENT (32 bytes). Offsets must point at message frame boundaries inside the term buffer; an unaligned offset would corrupt frame parsing. This is thrown after the range check and before the value is stored.

Solutions

  1. Round the offset down to the frame alignment: offset & ~(FRAME_ALIGNMENT - 1) with FRAME_ALIGNMENT=32
  2. Use initialPosition(...) with an already-aligned position so the offset is derived correctly
  3. Verify that whatever produced the offset aligns positions to 32-byte frames

Example fix

// before
builder.termOffset(100); // not multiple of 32
// after
builder.termOffset(96); // 100 & ~31 == 96
Defensive patterns

Strategy: validation

Validate before calling

int FRAME_ALIGNMENT = 32;
if (termOffset != null && (termOffset & (FRAME_ALIGNMENT - 1)) != 0) termOffset &= ~(FRAME_ALIGNMENT - 1);

Try / catch

try { builder.termOffset(offset); } catch (IllegalArgumentException e) { builder.termOffset(offset & ~31); }

Prevention

When it happens

Trigger: Calling termOffset() with any value not divisible by 32, e.g. termOffset(100), or URIs with 'term-offset=50'.

Common situations: Deriving offsets from raw stream positions without aligning to frame boundaries; manually tuning replay/resume points; constructing URIs from arbitrary recorded positions.

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


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/5aa0e86436e22e16. Report an issue: GitHub.

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/ChannelUriStringBuilder.java:843

     * Set the offset within a term at which a publication will start. This when combined with the term id can establish
     * a starting position.
     *
     * @param termOffset within a term at which a publication will start.
     * @return this for a fluent API.
     * @see CommonContext#TERM_OFFSET_PARAM_NAME
     */
    public ChannelUriStringBuilder termOffset(final Integer termOffset)
    {
        if (null != termOffset)
        {
            if ((termOffset < 0 || termOffset > TERM_MAX_LENGTH))
            {
                throw new IllegalArgumentException("term offset not in range 0-1g: " + termOffset);
            }

            if (0 != (termOffset & (FRAME_ALIGNMENT - 1)))
            {
                throw new IllegalArgumentException("term offset not multiple of FRAME_ALIGNMENT: " + termOffset);
            }
        }

        this.termOffset = termOffset;
        return this;
    }

    /**
     * Set the termOffset value to be what is in the {@link ChannelUri} which may be null.
     *
     * @param channelUri to read the value from.
     * @return this for a fluent API.
     * @see CommonContext#TERM_OFFSET_PARAM_NAME
     */
    public ChannelUriStringBuilder termOffset(final ChannelUri channelUri)
    {
        final String termOffsetValue = channelUri.get(TERM_OFFSET_PARAM_NAME);
        if (null == termOffsetValue)

View on GitHub (pinned to 6d60124e15)