{"record":{"id":"ce9863515f9bbc34","repo":"apache/druid","slug":"failed-to-stop-mainthread-couldn-t-finish","errorCode":null,"errorMessage":"failed to stop, mainThread couldn't finish.","messagePattern":"failed to stop, mainThread couldn't finish\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java","lineNumber":249,"sourceCode":"  }\n\n  @LifecycleStop\n  public void stop()\n  {\n    if (!lifecycleLock.canStop()) {\n      throw new ISE(\"can't stop.\");\n    }\n\n    LOG.debug(\"LookupExtractorFactoryContainerProvider is stopping.\");\n\n    if (!testMode) {\n      mainThread.interrupt();\n\n      try {\n        mainThread.join();\n      }\n      catch (InterruptedException ex) {\n        throw new ISE(\"failed to stop, mainThread couldn't finish.\");\n      }\n    }\n\n    for (Map.Entry<String, LookupExtractorFactoryContainer> e : stateRef.get().lookupMap.entrySet()) {\n      try {\n        if (e.getValue().getLookupExtractorFactory().close()) {\n          LOG.info(\"Closed lookup [%s].\", e.getKey());\n        } else {\n          LOG.error(\"Failed to close lookup [%s].\", e.getKey());\n        }\n      }\n      catch (Exception ex) {\n        LOG.error(ex, \"Failed to close lookup [%s].\", e.getKey());\n      }\n    }\n    lookupUpdateExecutorService.shutdown();\n    LOG.debug(\"LookupExtractorFactoryContainerProvider is stopped.\");\n  }","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java#L231-L267","documentation":"Thrown by LookupReferencesManager.stop() when the main processing thread, after being interrupted, throws InterruptedException from mainThread.join(). It indicates the lookup manager's background thread could not be confirmed terminated during shutdown, so stop() aborts with an IllegalStateException rather than closing lookups from an unknown state.","triggerScenarios":"Calling stop() (LifecycleStop) in non-testMode when mainThread.interrupt() leaves the background thread alive and the caller's own interrupt status is re-set while joining, so join() throws InterruptedException.","commonSituations":"Coordinator/lookup node shutdown where the main loop is stuck in a long blocking call that swallows interrupts; another thread interrupts the stopping thread during shutdown; JVM shutdown hooks racing with lifecycle stop.","solutions":["Investigate why mainThread is unresponsive to interrupt (blocking I/O or swallowed InterruptedException) and ensure its loop exits on interrupt.","Check for other threads repeatedly interrupting the stopping thread during shutdown.","Ensure stop() is not called concurrently from multiple lifecycle hooks.","If this occurs during tests, verify testMode is set correctly so the main thread path is not exercised."],"exampleFix":"// before: main loop swallows interrupts\nwhile (!Thread.currentThread().isInterrupted()) {\n  try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) { /* ignore */ }\n}\n// after: honor interrupt and exit\nwhile (!Thread.currentThread().isInterrupted()) {\n  try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) {\n    Thread.currentThread().interrupt();\n    break;\n  }\n}","handlingStrategy":"try-catch","validationCode":"if (manager.isStarted()) { /* ensure no concurrent stop() calls; check main thread alive before stop */ }","typeGuard":null,"tryCatchPattern":"try { manager.stop(); } catch (IllegalStateException e) { LOG.warn(\"lookup manager stop failed: %s\", e.getMessage()); /* proceed with shutdown; close lookup factories manually */ }","preventionTips":["Ensure the lookup manager main loop exits promptly on interrupt","Avoid other threads interrupting the thread calling stop()","Call stop() only once from the lifecycle shutdown path","Use testMode in unit tests to skip the main-thread join path"],"tags":["lifecycle","shutdown","threading","interrupted"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}