alibaba/nacos · warning · NoSuchElementException

The subscriber has no event publisher

Error message

The subscriber has no event publisher

What it means

Thrown by NotifyCenter when unregistering a subscriber that has no associated publisher: the subscriber's subscribeType is not a SlowEvent, it is not in the shared publisher, and removeSubscriber returned false. NoSuchElementException indicates a logic error in subscriber registration/unregistration pairing rather than a transport problem.

Source

Thrown at common/src/main/java/com/alibaba/nacos/common/notify/NotifyCenter.java:251

                if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {
                    INSTANCE.sharePublisher.removeSubscriber(consumer, subscribeType);
                } else {
                    removeSubscriber(consumer, subscribeType);
                }
            }
            return;
        }
        
        final Class<? extends Event> subscribeType = consumer.subscribeType();
        if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {
            INSTANCE.sharePublisher.removeSubscriber(consumer, subscribeType);
            return;
        }
        
        if (removeSubscriber(consumer, subscribeType)) {
            return;
        }
        throw new NoSuchElementException("The subscriber has no event publisher");
    }
    
    /**
     * Remove subscriber.
     *
     * @param consumer      subscriber instance.
     * @param subscribeType subscribeType.
     * @return whether remove subscriber successfully or not.
     */
    private static boolean removeSubscriber(final Subscriber consumer,
        Class<? extends Event> subscribeType) {
        
        final String topic = ClassUtils.getCanonicalName(subscribeType);
        EventPublisher eventPublisher = INSTANCE.publisherMap.get(topic);
        if (null == eventPublisher) {
            return false;
        }
        if (eventPublisher instanceof ShardedEventPublisher) {

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Match the subscribeType passed to removal with the one used at registration; reuse the same Subscriber instance.
  2. Guard removal: track registered subscribers and only call deregister for ones you actually registered.
  3. Wrap deregistration in try/catch(NoSuchElementException) during teardown so a mismatch does not abort cleanup of other subscribers.
  4. Register/unregister symmetrically in component lifecycle start/stop methods.

Example fix

// before
NotifyCenter.deregisterSubscriber(sub); // throws if sub was never registered for its type

// after
try {
    NotifyCenter.deregisterSubscriber(sub);
} catch (NoSuchElementException e) {
    LOG.debug("Subscriber {} already removed for {}", sub, sub.subscribeType());
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (registeredSubscribers.remove(consumer)) {
    NotifyCenter.deregisterSubscriber(consumer);
}

Try / catch

try {
    NotifyCenter.deregisterSubscriber(consumer);
} catch (NoSuchElementException e) {
    log.debug("Subscriber {} not registered, ignoring", consumer);
}

Prevention

When it happens

Trigger: Calling NotifyCenter.deregisterSubscriber(consumer)/removeSubscriber for a subscriber/subscribeType combination that was never registered, was already removed, or was registered under a different event type than the one passed at removal.

Common situations: Double-unregistering the same subscriber; unregistering with a subscribeType that differs from the one used at registration; subscriber registered via the SlowEvent shared path but removed via the per-type path (or vice versa); cleanup code running for components that were never wired.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/8d56f576e43f340c. Report an issue: GitHub.