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

  1. Unregister the existing handler first via chatHandlerProvider.unregister(service, handler) before re-registering
  2. Ensure the registration code path runs only once per JVM lifecycle
  3. Use a unique service name per handler instance if multiple handlers are needed
  4. 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

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)