{"record":{"id":"7c9117fe569adc2d","repo":"oracle/graal","slug":"interrupted-while-waiting-for-housekeeping-thread","errorCode":null,"errorMessage":"Interrupted while waiting for housekeeping thread shutdown.","messagePattern":"Interrupted while waiting for housekeeping thread shutdown\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java","lineNumber":835,"sourceCode":"            } else {\n                if (sizeClass >= missedHashChildrenRequestCounts.length()) {\n                    throw INTERNAL_FAILURE_EXCEPTION;\n                }\n                missedHashChildrenRequestCounts.incrementAndGet(sizeClass);\n                throw FAILED_ALLOCATION_EXCEPTION;\n            }\n        }\n\n        /**\n         * @since 23.0\n         */\n        @Override\n        public void shutdown() {\n            housekeepingThread.isEnabled.set(false);\n            try {\n                housekeepingThread.join();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(\"Interrupted while waiting for housekeeping thread shutdown.\", e);\n            }\n        }\n\n        public String status() {\n            StringBuilder content = new StringBuilder();\n            content.append(\"ObjectPoolingAllocator\").append(System.lineSeparator());\n            content.append(\"======================\").append(System.lineSeparator());\n\n            // Misses statistics.\n            content.append(\"  current node alloc misses:      \").append(missedNodePoolRequestCount.get()).append(System.lineSeparator());\n            content.append(\"  current linear children misses: \").append(System.lineSeparator());\n            content.append(\"    size class \");\n            for (int sizeClass = 0; sizeClass < SIZE_CLASS_COUNT; sizeClass++) {\n                content.append(String.format(\"%4d\", sizeClass));\n            }\n            content.append(System.lineSeparator());\n            content.append(\"    miss count \");\n            for (int sizeClass = 0; sizeClass < SIZE_CLASS_COUNT; sizeClass++) {","sourceCodeStart":817,"sourceCodeEnd":853,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/sdk/src/org.graalvm.collections/src/org/graalvm/collections/LockFreePrefixTree.java#L817-L853","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nexecutor.shutdownNow(); // interrupts tasks\nalloc.shutdown(); // inside interrupted task -> RuntimeException\n\n// after\nThread.interrupted(); // clear any pending interrupt flag\nalloc.shutdown();","handlingStrategy":"try-catch","validationCode":"Thread.interrupted(); // clear flag before shutdown\nalloc.shutdown();","typeGuard":null,"tryCatchPattern":"try {\n    alloc.shutdown();\n} catch (RuntimeException e) {\n    if (e.getCause() instanceof InterruptedException) {\n        Thread.currentThread().interrupt(); // restore flag\n        // shutdown was signalled; optionally re-join with a bounded wait\n    } else {\n        throw e;\n    }\n}","preventionTips":["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."],"tags":["graalvm","collections","concurrency","interrupt","prefix-tree"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}