aeron-io/aeron · error · IllegalArgumentException

invalid position: " + position

Error message

invalid position: " + position

What it means

RecordingReader validates replay parameters against the recording's metadata. A position below NULL_POSITION (i.e. a negative sentinel misuse) is not a valid replay start, so an IllegalArgumentException is thrown at construction time.

Solutions

  1. Pass Aeron.NULL_POSITION (-1) to mean 'from the recording start', not arbitrary negative numbers.
  2. Validate/clamp the requested replay position client-side before sending the replay request.
  3. Check the code computing the position for sign or sentinel confusion.
  4. Log the requested recordingId and position to identify the bad caller.

Example fix

// before
long position = -2; // intended 'from start'
// after
long position = Aeron.NULL_POSITION; // -1 means replay from start
Defensive patterns

Strategy: validation

Validate before calling

if (position != Aeron.NULL_POSITION && position < 0) {
    throw new IllegalArgumentException("position must be Aeron.NULL_POSITION or >= 0");
}

Try / catch

try { replay(recId, position, length); }
catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("invalid position")) { fixSentinelAndRetry(); }
}

Prevention

When it happens

Trigger: Constructing RecordingReader (via the archive conductor's replay path) with position < Aeron.NULL_VALUE, e.g. passing -2/-3 or a miscomputed sentinel instead of NULL_POSITION (-1) to mean 'replay from start'.

Common situations: Client passes a negative replay position in a replay request; arithmetic bug computing start position; confusing NULL_POSITION with other Aeron sentinels like NULL_VALUE.

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/492463600548c4d6. Report an issue: GitHub.

Appendix: source

Thrown at aeron-archive/src/main/java/io/aeron/archive/RecordingReader.java:65

    private final int segmentLength;
    private final int termLength;

    private final UnsafeBuffer termBuffer;
    private MappedByteBuffer mappedSegmentBuffer;

    private final long replayLimit;
    private long replayPosition;
    private long segmentFilePosition;
    private int termOffset;
    private int termBaseSegmentOffset;
    private boolean isDone = false;

    RecordingReader(
        final RecordingSummary recordingSummary, final File archiveDir, final long position, final long length)
    {
        if (position < NULL_POSITION)
        {
            throw new IllegalArgumentException("invalid position: " + position);
        }

        if (length < NULL_LENGTH)
        {
            throw new IllegalArgumentException("invalid length: " + length);
        }

        this.archiveDir = archiveDir;
        this.termLength = recordingSummary.termBufferLength;
        this.segmentLength = recordingSummary.segmentFileLength;
        this.recordingId = recordingSummary.recordingId;

        final long startPosition = recordingSummary.startPosition;
        final long fromPosition = position == NULL_POSITION ? startPosition : position;
        final long maxLength = recordingSummary.stopPosition != NULL_POSITION ?
            recordingSummary.stopPosition - fromPosition : Long.MAX_VALUE - fromPosition;

        final long replayLength = length == NULL_LENGTH ? maxLength : Math.min(length, maxLength);

View on GitHub (pinned to 6d60124e15)