apache/pulsar · warning · IOException

Interrupted while preloading

Error message

Interrupted while preloading

What it means

IOException 'Interrupted while preloading' thrown by LegacyHierarchicalLedgerRangeIterator.preload when the thread blocking on the metadata-store future is interrupted. The method restores the interrupt flag before throwing, so callers retain correct interruption semantics.

Source

Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/bookkeeper/LegacyHierarchicalLedgerRangeIterator.java:118

        while (nextRange == null && !iteratorDone) {
            boolean hasMoreElements = false;
            try {
                if (l1NodesIter == null) {
                    List<String> l1Nodes = store.sync(ledgersRoot)
                            .thenCompose(__ -> store.getChildrenFromStore(ledgersRoot))
                            .get(BLOCKING_CALL_TIMEOUT, MILLISECONDS);
                    l1NodesIter = l1Nodes.iterator();
                    hasMoreElements = nextL1Node();
                } else if (l2NodesIter == null || !l2NodesIter.hasNext()) {
                    hasMoreElements = nextL1Node();
                } else {
                    hasMoreElements = true;
                }
            } catch (ExecutionException | TimeoutException ke) {
                throw new IOException("Error preloading next range", ke);
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                throw new IOException("Interrupted while preloading", ie);
            }
            if (hasMoreElements) {
                nextRange = getLedgerRangeByLevel(curL1Nodes, l2NodesIter.next());
                if (nextRange.size() == 0) {
                    nextRange = null;
                }
            } else {
                iteratorDone = true;
            }
        }
    }

    @Override
    public synchronized boolean hasNext() throws IOException {
        preload();
        return nextRange != null && !iteratorDone;
    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Let shutdown complete cleanly — stop driving the iterator after interruption and exit the loop
  2. Avoid interrupting worker threads mid-enumeration; coordinate shutdown before cancelling tasks
  3. If interruption is unexpected, audit which executor/task lifecycle interrupts this thread

Example fix

// before
while (it.hasNext()) { ... } // throws IOException 'Interrupted while preloading' on shutdown
// after
while (!Thread.currentThread().isInterrupted() && it.hasNext()) {
    ...
}
// or handle:
try {
    while (it.hasNext()) { ... }
} catch (IOException e) {
    if (Thread.currentThread().isInterrupted()) return; // expected shutdown
    throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (Thread.currentThread().isInterrupted()) { return; /* skip enumeration */ }

Try / catch

try {
    while (it.hasNext()) { ... }
} catch (IOException e) {
    if (Thread.currentThread().isInterrupted()) {
        return; // expected during shutdown — do not log as failure
    }
    throw e;
}

Prevention

When it happens

Trigger: hasNext() triggers preload(); the thread waiting on .get(BLOCKING_CALL_TIMEOUT) is interrupted, typically during shutdown or when the task is cancelled.

Common situations: Broker/service shutdown while a ledger-enumeration loop is active; executor shutdownNow() cancelling the worker thread; test timeouts interrupting the test thread.

Related errors


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