apache/druid · error · IllegalStateException
handler already registered for service
Error message
handler already registered for service[%s]
What it means
ChatHandlerProviderImpl keeps a map from service name to ChatHandler. register() throws this ISE when a handler is already registered under the same service name, because putIfAbsent returns the existing entry — Druid does not allow silent replacement of chat handlers.
Solutions
- Unregister the existing handler first via chatHandlerProvider.unregister(service, handler) before re-registering
- Ensure the registration code path runs only once per JVM lifecycle
- Use a unique service name per handler instance if multiple handlers are needed
- If intentionally replacing, refactor to explicitly close the old handler and unregister before creating the new one
Example fix
// before chatHandlerProvider.register(service, handler); // throws if already present // after chatHandlerProvider.unregister(service, handler); chatHandlerProvider.register(service, handler);
Defensive patterns
Strategy: validation
Validate before calling
if (chatHandlerProvider.get(service) != null) {
chatHandlerProvider.unregister(service, existingHandler);
}
chatHandlerProvider.register(service, handler); Try / catch
try {
chatHandlerProvider.register(service, handler);
} catch (ISE e) {
log.warn(e, "Handler already registered for %s", service);
} Prevention
- Register each ChatHandler exactly once per JVM lifecycle
- Use unique service names per handler instance
- Call unregister in your lifecycle stop/shutdown hook
When it happens
Trigger: Calling chatHandlerProvider.register(service, handler) twice with the same service string — e.g. re-initializing a task/runners within the same JVM, or two handlers registered with an identical service name.
Common situations: Kafka/Kinesis indexing tasks restarted in the same JVM lifecycle; a custom extension registering handlers with a name that collides with a built-in one; double registration due to lifecycle hooks firing twice.
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/c8bc38210651f31f.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/main/java/org/apache/druid/segment/realtime/ChatHandlerProvider.java:58
@Inject
public ChatHandlerProvider()
{
this.handlers = new ConcurrentHashMap<>();
}
/**
* Registers a chat handler which provides an API for others to talk to objects in the indexing service.
*
* @param service a unique name identifying this service
* @param handler instance which implements the API to be exposed
*/
public void register(final String service, ChatHandler handler)
{
log.debug("Registering Eventhandler[%s]", service);
if (handlers.putIfAbsent(service, handler) != null) {
throw new ISE("handler already registered for service[%s]", service);
}
}
/**
* Unregisters a chat handler.
*
* @param service the name of the service
*/
public void unregister(final String service)
{
log.debug("Unregistering chat handler[%s]", service);
final ChatHandler handler = handlers.get(service);
if (handler == null) {
log.warn("handler[%s] not currently registered, ignoring.", service);
return;
}
View on GitHub (pinned to 9b90983fd2)