pinpoint-apm/pinpoint · error · IllegalStateException
Scanner is exhausted, cannot call next() again
Error message
Scanner is exhausted, cannot call next() again
What it means
LocalScannerImpl wraps a per-region ResultScanner for the row-distributor (WD) scanner. Once the underlying scanner returns null it is marked exhausted; calling next() again is a contract violation for ResultScanner semantics and throws IllegalStateException to prevent returning stale or bogus rows.
Solutions
- Stop iterating as soon as next() returns null
- Obtain a new scanner (via the WD scanner factory) instead of reusing an exhausted one
- Check for duplicate next() calls in retry/loop logic around ResultScanner usage
Example fix
// before
Result r = scanner.next();
process(r);
Result r2 = scanner.next(); // may throw if already exhausted
// after
Result r;
while ((r = scanner.next()) != null) { process(r); } Defensive patterns
Strategy: validation
Try / catch
try {
Result r = localScanner.next();
} catch (IllegalStateException e) {
logger.error("Scanner misuse: {}", e.getMessage());
scanner = wdScanner.getScanner(region); // reacquire instead of reusing
} Prevention
- Treat next()==null as terminal; never call next() again afterwards
- Always use while ((r = scanner.next()) != null) loops
- Don't cache and reuse ResultScanner instances after completion
- Reset local scanner state when reusing wrapper objects
When it happens
Trigger: Calling next() on a LocalScannerImpl after a previous next() returned null (end of the wrapped region's results), e.g. a loop that doesn't break on null or retries after exhaustion.
Common situations: Consumer loops calling next() once more to 'confirm' the end; code caching the scanner and reusing it after completion; bugs in aggregate logic over WD-scanned regions.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Already closed
- Cannot add an existing column family :
- Cannot create an existing table :
- Cannot modify a non-existent table :
- ColumnFamily name must not be empty
AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07).
Data as JSON: /api/errors/58c7de1b4e95d9ed.
Report an issue: GitHub.
Appendix: source
Thrown at commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/wd/LocalScannerImpl.java:50
* callers to peek at the next {@link Result} and query exhaustion state before
* consuming it.
*/
public class LocalScannerImpl implements Closeable, LocalScanner {
private final ResultScanner scanner;
private boolean exhausted = false;
private Result localBuffer;
public LocalScannerImpl(ResultScanner scanner) {
this.scanner = Objects.requireNonNull(scanner, "scanner");
}
@Override
public Result next() throws IOException {
if (exhausted) {
throw new IllegalStateException("Scanner is exhausted, cannot call next() again");
}
if (localBuffer != null) {
return localBuffer;
}
Result next = scanner.next();
if (next == null) {
exhausted = true;
}
localBuffer = next;
return localBuffer;
}
@Override
public boolean isExhausted() {
return exhausted;
}
@OverrideView on GitHub (pinned to 744c3d3075)