apache/pulsar · error · IOException

Error seeking, new position %d < current position %d

Error message

Error seeking, new position %d < current position %d

What it means

BlobStoreBackedInputStreamImpl is a forward-only stream over offloaded ledger data; seekForward(position) must never move the cursor backwards. If a caller requests a position earlier than the current cursor, it throws an IOException since the buffer cannot rewind what has already been consumed.

Source

Thrown at tiered-storage/jcloud/src/main/java/org/apache/bookkeeper/mledger/offload/jcloud/impl/BlobStoreBackedInputStreamImpl.java:188

        log.debug().attr("position", position).attr("bucket", bucket).attr("key", key)
                .attr("cursor", cursor).attr("bufStart", bufferOffsetStart)
                .attr("bufEnd", bufferOffsetEnd).log("Seeking");
        if (position >= bufferOffsetStart && position <= bufferOffsetEnd) {
            long newIndex = position - bufferOffsetStart;
            buffer.readerIndex((int) newIndex);
        } else {
            bufferOffsetStart = bufferOffsetEnd = -1;
            this.cursor = position;
            buffer.clear();
        }
    }

    @Override
    public void seekForward(long position) throws IOException {
        if (position >= cursor) {
            seek(position);
        } else {
            throw new IOException(String.format("Error seeking, new position %d < current position %d",
                                                position, cursor));
        }
    }

    public long getCurrentPosition() {
        if (bufferOffsetStart != -1) {
            return bufferOffsetStart + buffer.readerIndex();
        }
        return cursor + buffer.readerIndex();
    }

    @Override
    public void close() {
        buffer.release();
    }

    @Override
    public int available() throws IOException {

View on GitHub (pinned to 820761864e)

Solutions

  1. Ensure callers only request monotonically increasing positions when reading offloaded ledgers; re-open a fresh ReadHandle if backward access is needed
  2. Fix entry-position computation so reads are issued in ascending order (verify offload thresholds and entry offsets)
  3. If a rewind is genuinely required, recreate the input stream/ReadHandle instead of seeking backward

Example fix

// before: rewind attempt
readHandle.seekForward(oldPosition); // throws
// after: reopen for backward reads
if (oldPosition < stream.getCurrentPosition()) {
  stream = reopenReadHandle(ledgerId);
}
stream.seekForward(oldPosition);
Defensive patterns

Strategy: validation

Validate before calling

// guard before seeking
long cur = stream.getCurrentPosition();
if (position < cur) {
  throw new IllegalArgumentException("cannot seek backward: " + position + " < " + cur);
}

Try / catch

try {
  stream.seekForward(position);
} catch (IOException e) {
  if (e.getMessage().contains("new position") && e.getMessage().contains("< current position")) {
    stream = reopenReadHandle(ledgerId); // rewind requires a fresh stream
  } else throw e;
}

Prevention

When it happens

Trigger: BookKeeper read-handle seek logic calls seekForward with a position smaller than the stream's current position — typically when ledger entry reads are issued out of order or a caller re-reads an entry already passed.

Common situations: Reading entries of an offloaded ledger non-monotonically (e.g. after a consumer/reader rewind or a wrong entry-id computation); caller caching stale entry positions and re-reading; bug in ReadHandle interpolation of offload positions.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/ca58568644c68cac. Report an issue: GitHub.