apache/druid · error · IllegalStateException
destroy method returned false for lookup
Error message
destroy method returned false for lookup [%s]:[%s]
What it means
dropContainer() removes a lookup: after logging, it calls the container's LookupExtractorFactory.destroy(). If destroy() returns false the lookup could not be torn down cleanly, so an IllegalStateException is thrown naming the lookup and container.
Solutions
- Ensure the factory is stopped/closed appropriately before destroy, or that destroy() is idempotent in the factory implementation.
- Check factory logs for the underlying reason destroy() returned false.
- Retry the drop after resources are released (the notice will be reprocessed or reissued).
- If a custom factory, fix destroy() to release resources or return true when already destroyed.
Example fix
// before: custom factory destroy always false while started
public boolean destroy() { if (started) { return false; } ... }
// after: stop then destroy
public boolean destroy() { if (started) { stop(); } resources.release(); return true; } Defensive patterns
Strategy: try-catch
Try / catch
try { manager.remove(name, container); } catch (IllegalStateException e) { if (e.getMessage().startsWith("destroy method returned false")) { LOG.warn("lookup %s not cleanly destroyed; will retry", name); retryDropLater(name, container); } else { throw e; } } Prevention
- Ensure factories implement idempotent destroy()
- Verify backing-store connectivity so cleanup can complete
- Avoid dropping lookups while their factories are mid-start
- Inspect factory logs for the false return's cause
When it happens
Trigger: handle() processing a DropNotice calls dropContainer(); the factory's destroy() returns false, e.g., the factory refuses to destroy because it is still started/in-use or its backing resources can't be released.
Common situations: Lookups still referenced/started when dropped; external store connection failure preventing resource cleanup; factory implementations returning false on non-fatal cleanup issues.
Related errors
- Already shut down, not starting again
- Already started, not starting again
- Cache reference is null
- can't start.
- can't stop.
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/8c3def731b444ad2.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/query/lookup/LookupReferencesManager.java:610
private LookupUpdateState atomicallyUpdateStateRef(Function<LookupUpdateState, LookupUpdateState> fn)
{
while (true) {
LookupUpdateState old = stateRef.get();
LookupUpdateState newState = fn.apply(old);
if (stateRef.compareAndSet(old, newState)) {
return newState;
}
}
}
private void dropContainer(LookupExtractorFactoryContainer container, String lookupName)
{
if (container != null) {
LOG.debug("Removed lookup [%s] with spec [%s].", lookupName, container);
if (!container.getLookupExtractorFactory().destroy()) {
throw new ISE(
"destroy method returned false for lookup [%s]:[%s]",
lookupName,
container
);
}
}
}
@VisibleForTesting
interface Notice
{
void handle(Map<String, LookupExtractorFactoryContainer> lookupMap, LookupReferencesManager manager)
throws Exception;
}
private static class LoadNotice implements Notice
{
private final String lookupName;View on GitHub (pinned to 9b90983fd2)