aeron-io/aeron · error · IllegalArgumentException

improperly formatted block:

Error message

improperly formatted block:

What it means

ExclusivePublication throws this IllegalArgumentException when a block's header fields read back from the buffer do not match the publication's own termOffset, sessionId, streamId, termId, or frame type. This means the block buffer supplied is not the correctly framed block the publication expects at its current position — an internal invariant/contract violation of the block append API.

Solutions

  1. Rebuild the block's frame header so termOffset, sessionId, streamId, termId, and frameType exactly match the publication's current values.
  2. Regenerate the block from current publication state instead of reusing a cached/stale buffer.
  3. Verify the frame type written into the header matches the expected block frame type (e.g. HDR_TYPE_DATA vs HDR_TYPE_PAD).

Example fix

// before
blockHeader.sessionId = oldSessionId; // stale
publication.tryAppendBlock(blockBuffer, 0, blockLength);
// after
blockHeader.termOffset = publication.termOffset();
blockHeader.sessionId = publication.sessionId();
blockHeader.streamId = publication.streamId();
blockHeader.termId = publication.termId();
publication.tryAppendBlock(blockBuffer, 0, blockLength);
Defensive patterns

Strategy: validation

Validate before calling

if (blockTermOffset != publication.termOffset() || blockSessionId != publication.sessionId() ||
    blockStreamId != publication.streamId() || blockTermId != publication.termId()) {
    throw new IllegalStateException("block header stale; rebuild before append");
}

Try / catch

try {
    publication.tryAppendBlock(blockBuffer, 0, blockLength);
} catch (IllegalArgumentException e) {
    // rebuild frame header from current publication state and retry
}

Prevention

When it happens

Trigger: Calling a block-append API with a buffer whose frame header was built for a different session/stream/term/offset, or with a buffer whose frameType does not match (e.g. PADDING vs DATA), or reusing stale buffers from a previous term.

Common situations: Manually constructing frame headers for raw block publication with wrong session or term IDs; passing buffers captured from a different image/publication; protocol-level tooling or replay code writing misaligned frames.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/ExclusivePublication.java:566

        }
    }

    private void checkFirstFrame(final MutableDirectBuffer buffer, final int offset)
    {
        final int frameType = HDR_TYPE_DATA;
        final int blockTermOffset = buffer.getInt(offset + TERM_OFFSET_FIELD_OFFSET, LITTLE_ENDIAN);
        final int blockSessionId = buffer.getInt(offset + SESSION_ID_FIELD_OFFSET, LITTLE_ENDIAN);
        final int blockStreamId = buffer.getInt(offset + STREAM_ID_FIELD_OFFSET, LITTLE_ENDIAN);
        final int blockTermId = buffer.getInt(offset + TERM_ID_FIELD_OFFSET, LITTLE_ENDIAN);
        final int blockFrameType = buffer.getShort(offset + TYPE_FIELD_OFFSET, LITTLE_ENDIAN) & 0xFFFF;

        if (blockTermOffset != termOffset ||
            blockSessionId != sessionId ||
            blockStreamId != streamId ||
            blockTermId != termId ||
            frameType != blockFrameType)
        {
            throw new IllegalArgumentException("improperly formatted block:" +
                " termOffset=" + blockTermOffset + " (expected=" + termOffset + ")," +
                " sessionId=" + blockSessionId + " (expected=" + sessionId + ")," +
                " streamId=" + blockStreamId + " (expected=" + streamId + ")," +
                " termId=" + blockTermId + " (expected=" + termId + ")," +
                " frameType=" + blockFrameType + " (expected=" + frameType + ")");
        }
    }

    private long newPosition(final int resultingOffset)
    {
        if (resultingOffset > 0)
        {
            termOffset = resultingOffset;
            return termBeginPosition + resultingOffset;
        }

        if ((termBeginPosition + termBufferLength) >= maxPossiblePosition)
        {

View on GitHub (pinned to 6d60124e15)