oracle/graal · error · RuntimeException
Interrupted while waiting for housekeeping thread shutdown.
Error message
Interrupted while waiting for housekeeping thread shutdown.
What it means
ObjectPoolingAllocator.shutdown() in LockFreePrefixTree stops the housekeeping thread and joins it; if the calling thread is interrupted while waiting in join(), the InterruptedException is wrapped in a RuntimeException with this message. Shutdown itself completed the disable signal; only the wait-for-exit was cut short, so the housekeeping thread may still be finishing asynchronously.
Source
Thrown at sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java:835
} else {
if (sizeClass >= missedHashChildrenRequestCounts.length()) {
throw INTERNAL_FAILURE_EXCEPTION;
}
missedHashChildrenRequestCounts.incrementAndGet(sizeClass);
throw FAILED_ALLOCATION_EXCEPTION;
}
}
/**
* @since 23.0
*/
@Override
public void shutdown() {
housekeepingThread.isEnabled.set(false);
try {
housekeepingThread.join();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while waiting for housekeeping thread shutdown.", e);
}
}
public String status() {
StringBuilder content = new StringBuilder();
content.append("ObjectPoolingAllocator").append(System.lineSeparator());
content.append("======================").append(System.lineSeparator());
// Misses statistics.
content.append(" current node alloc misses: ").append(missedNodePoolRequestCount.get()).append(System.lineSeparator());
content.append(" current linear children misses: ").append(System.lineSeparator());
content.append(" size class ");
for (int sizeClass = 0; sizeClass < SIZE_CLASS_COUNT; sizeClass++) {
content.append(String.format("%4d", sizeClass));
}
content.append(System.lineSeparator());
content.append(" miss count ");
for (int sizeClass = 0; sizeClass < SIZE_CLASS_COUNT; sizeClass++) {View on GitHub (pinned to a66e9ccd1d)
Solutions
- Clear or handle the interrupt before calling shutdown(): check and consume Thread.interrupted(), or call shutdown() outside interrupt scope.
- Catch the RuntimeException and, if needed, re-check the housekeeping thread with a bounded join() after clearing the interrupt flag.
- Restructure so shutdown() is invoked from a non-interruptible context (dedicated closer thread or before executor shutdown).
Example fix
// before executor.shutdownNow(); // interrupts tasks alloc.shutdown(); // inside interrupted task -> RuntimeException // after Thread.interrupted(); // clear any pending interrupt flag alloc.shutdown();
Defensive patterns
Strategy: try-catch
Validate before calling
Thread.interrupted(); // clear flag before shutdown alloc.shutdown();
Try / catch
try {
alloc.shutdown();
} catch (RuntimeException e) {
if (e.getCause() instanceof InterruptedException) {
Thread.currentThread().interrupt(); // restore flag
// shutdown was signalled; optionally re-join with a bounded wait
} else {
throw e;
}
} Prevention
- Do not call shutdown() from threads subject to cancellation interrupts.
- Call shutdown() before executor.shutdownNow(), not after.
- Clear pending interrupt flags before joining long-running helper threads.
When it happens
Trigger: Calling shutdown() on the allocator while the calling thread's interrupt flag is set (e.g. inside a task cancelled by an ExecutorService, or after Thread.interrupt() from a timeout watchdog). Also when shutdown() races with JVM shutdown hooks that interrupt threads.
Common situations: Running the prefix tree inside thread pools that cancel tasks on timeout; test harnesses that interrupt workers between phases; shutdown hooks racing with executor.shutdownNow(), which interrupts pending tasks.
Related errors
- Allocator's housekeeping thread was interrupted.
- endless collision link cycle, most likely due to unsynchroni
- Key in the prefix tree cannot be 0.
- Cannot signal lock that is not held
- You can't resume an already executing continuation.
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/7c9117fe569adc2d.
Report an issue: GitHub.