apache/druid · error · IllegalStateException
Lifecycle has already started.
Error message
Lifecycle has already started.
What it means
registerSegmentCallback(Executor, SegmentCallback, Predicate) must be invoked before the server inventory view starts. Once lifecycleLock.isStarted() is true, registering new callbacks is rejected with ISE because the registration maps feed the sync executor only at startup.
Solutions
- Register all callbacks before calling start() or before the Lifecycle begins
- Restructure so callbacks are known at construction time and passed via configuration/DI
- Use a fresh HttpServerInventoryView instance if registration must happen later
- If dynamic registration is needed, wrap the callback to change its behavior rather than re-registering
Example fix
// before view.start(); view.registerSegmentCallback(exec, cb, filter); // ISE // after view.registerSegmentCallback(exec, cb, filter); view.start();
Defensive patterns
Strategy: validation
Validate before calling
// register only before start if (!isStarted) view.registerSegmentCallback(exec, cb, filter);
Prevention
- Register all callbacks during initialization before Lifecycle.start
- Pass callbacks via constructor/DI rather than late registration
- Keep a startup checklist ordering: register -> start
When it happens
Trigger: Calling the filtered registerSegmentCallback after start() has run (or after the enclosing Lifecycle started the view).
Common situations: Broker extension plugins adding segment filters lazily after service startup; race between a management thread and lifecycle startup; tests that add callbacks in @BeforeEach while a shared instance was already started.
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
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/ab6f38c343fb479b.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/client/HttpServerInventoryView.java:285
inventorySyncExecutor.shutdownNow();
}
if (monitoringExecutor != null) {
monitoringExecutor.shutdownNow();
}
log.info("Stopped executor[%s].", execNamePrefix);
}
}
@Override
public void registerSegmentCallback(
Executor exec,
SegmentCallback callback,
Predicate<Pair<DruidServerMetadata, DataSegment>> filter
)
{
if (lifecycleLock.isStarted()) {
throw new ISE("Lifecycle has already started.");
}
SegmentCallback filteringSegmentCallback = new FilteringSegmentCallback(callback, filter);
segmentCallbacks.put(filteringSegmentCallback, exec);
segmentPredicates.put(filteringSegmentCallback, filter);
updateFinalPredicate();
}
@Override
public void registerServerCallback(Executor exec, ServerCallback callback)
{
if (lifecycleLock.isStarted()) {
throw new ISE("Lifecycle has already started.");
}
serverCallbacks.put(callback, exec);
}View on GitHub (pinned to 9b90983fd2)