{"record":{"id":"ba06f8fae8a22dbe","repo":"aeron-io/aeron","slug":"fromposition-position-not-aligned-to-valid-fragment","errorCode":null,"errorMessage":"fromPosition + \" position not aligned to valid fragment","messagePattern":"fromPosition \\+ \" position not aligned to valid fragment","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"aeron-archive/src/main/java/io/aeron/archive/RecordingReader.java","lineNumber":107,"sourceCode":"        final int positionBitsToShift = LogBufferDescriptor.positionBitsToShift(termLength);\n        final long startTermBasePosition = startPosition - (startPosition & (termLength - 1));\n        final int segmentOffset = (int)(fromPosition - startTermBasePosition) & (segmentLength - 1);\n        final int termId = ((int)(fromPosition >> positionBitsToShift) + recordingSummary.initialTermId);\n\n        segmentFilePosition = segmentFileBasePosition(startPosition, fromPosition, termLength, segmentLength);\n        openRecordingSegment();\n\n        termOffset = (int)(fromPosition & (termLength - 1));\n        termBaseSegmentOffset = segmentOffset - termOffset;\n        termBuffer = new UnsafeBuffer(mappedSegmentBuffer, termBaseSegmentOffset, termLength);\n\n        if (fromPosition > startPosition &&\n            (DataHeaderFlyweight.termOffset(termBuffer, termOffset) != termOffset ||\n            DataHeaderFlyweight.termId(termBuffer, termOffset) != termId ||\n            DataHeaderFlyweight.streamId(termBuffer, termOffset) != recordingSummary.streamId))\n        {\n            close();\n            throw new IllegalArgumentException(fromPosition + \" position not aligned to valid fragment\");\n        }\n\n        replayPosition = fromPosition;\n        replayLimit = fromPosition + replayLength;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void close()\n    {\n        closeRecordingSegment();\n    }\n\n    long replayPosition()\n    {\n        return replayPosition;","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-archive/src/main/java/io/aeron/archive/RecordingReader.java#L89-L125","documentation":"When replay starts after the recording's startPosition, the constructor checks that fromPosition points at a valid fragment by comparing the data header's termOffset, termId and streamId at that location. If fromPosition is not aligned to an actual fragment boundary (or belongs to a different stream), the reader closes its resources and throws IllegalArgumentException.","triggerScenarios":"Requesting a replay from a position that was never a fragment start — an arbitrary byte offset, a position from a different recording/stream, or a padded/batch boundary rather than a fragment boundary.","commonSituations":"Client guessed a resume position instead of tracking the last received fragment position; reusing positions recorded from a different streamId; resuming after archive restart with mismatched term metadata.","solutions":["Resume replays only from positions previously reported as fragment boundaries (e.g. last position from a previous replay or recording progress).","Ensure the streamId in the replay request matches the recorded stream.","Use boundedReplay/replay with NULL_POSITION to start from the beginning instead of guessing offsets.","Capture positions via the recording events/recording descriptor APIs rather than manual arithmetic."],"exampleFix":"// before\nlong resumeAt = lastKnownPosition + 123; // arbitrary offset\n// after\nlong resumeAt = lastFragmentPosition; // position previously reported by replay/callbacks\narchive.startReplay(recordingId, resumeAt, Aeron.NULL_LENGTH, channel, streamId);","handlingStrategy":"validation","validationCode":"// only resume from positions that were reported as fragment boundaries\nif (resumePosition > startPosition && !positionsFromCallbacks.contains(resumePosition)) {\n    resumePosition = Aeron.NULL_POSITION; // fall back to start\n}","typeGuard":null,"tryCatchPattern":"try { replay(recId, from, len); }\ncatch (IllegalArgumentException e) {\n    if (e.getMessage().endsWith(\"position not aligned to valid fragment\")) {\n        replayFromLastKnownBoundary(recId);\n    }\n}","preventionTips":["Track fragment-boundary positions from replay callbacks instead of guessing offsets.","Never resume from a position obtained on a different streamId or recording.","Store the last delivered position durably for resumable replays."],"tags":["replay","alignment","fragment","archive"],"backgroundTag":"invalid-argument-value","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}