hibernate/hibernate-orm · error · EventListenerRegistrationException

Listener did not implement expected interface [

Error message

Listener did not implement expected interface [

What it means

EventListenerRegistrationException from EventListenerGroupImpl.checkAgainstBaseInterface, run via prepareListener before a listener enters an event chain: the listener does not implement eventType.baseListenerInterface() for the group it is being added to. The event system dispatches by casting to the per-event interface, so a mismatched listener cannot be fired and is rejected. Generics on EventListenerGroup<T> normally catch this at compile time; the runtime check exists for raw-type and reflection-driven registrations.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java:361

		// we did not find any match, add it
		checkAgainstBaseInterface( listener );
		additionHandler.accept( listener );
	}

	@SuppressWarnings("unchecked")
	@AllowReflection // Possible array types are registered in org.hibernate.graalvm.internal.StaticClassLists.typesNeedingArrayCopy
	@Nonnull
	private T[] createListenerArrayForWrite(int len) {
		return (T[]) Array.newInstance( eventType.baseListenerInterface(), len );
	}

	private void prepareListener(@Nonnull T listener) {
		checkAgainstBaseInterface( listener );
	}

	private void checkAgainstBaseInterface(@Nonnull T listener) {
		if ( !eventType.baseListenerInterface().isInstance( listener ) ) {
			throw new EventListenerRegistrationException( "Listener did not implement expected interface ["
					+ eventType.baseListenerInterface().getName() + "]" );
		}
	}

	/**
	 * Implementation note: should be final for performance reasons.
	 * @deprecated this is not the most efficient way for iterating the event listeners.
	 * See {@link #fireEventOnEachListener(Object, BiConsumer)} and co. for better alternatives.
	 */
	@Override
	@Deprecated
	public final @Nonnull Iterable<T> listeners() {
		return listenersAsList;
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Register each listener only on the EventListenerGroup whose EventType's baseListenerInterface it implements (PersistEventListener -> EventType.PERSIST, PostLoadEventListener -> EventType.POST_LOAD, etc.)
  2. Keep EventListenerGroup<T> generic in your code — avoid raw types so mismatches fail at compile time
  3. Make proxy/decorator wrappers implement the same listener interface as the wrapped instance (or skip wrapping)

Example fix

// before
EventListenerGroup raw = registry.getEventListenerGroup(EventType.POST_INSERT);
raw.appendListeners(new MyPostLoadListener()); // raw type hides mismatch -> Listener did not implement expected interface

// after
EventListenerGroup<PostInsertEventListener> g = registry.getEventListenerGroup(EventType.POST_INSERT);
g.appendListeners(new MyPostInsertListener()); // compiles only when types line up
Defensive patterns

Strategy: type-guard

Validate before calling

null

Type guard

boolean implementsBase(EventType<?> type, Object listener) {
    return type.baseListenerInterface().isInstance(listener);
}
// EventType#baseListenerInterface is public; call before appendListeners

Try / catch

try {
    group.appendListeners(listener);
} catch (EventListenerRegistrationException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Listener did not implement")) {
        // wrong group or wrong listener class — fix the EventType/listener pairing
    }
    throw e;
}

Prevention

When it happens

Trigger: Appending a listener to the wrong group — e.g. adding a PostInsertEventListener to the EventType.POST_LOAD group; using raw EventListenerGroup types (unchecked appendListeners) so the compiler cannot police the type; listener wrappers/proxies (metrics, tracing) that fail to implement the original listener interface; integrations that look up groups by EventType but construct listeners of a different family.

Common situations: Copy-pasted integration code where the EventType constant and listener class no longer match; upgrading Hibernate across majors where listener interfaces moved between packages and the adapter now implements the wrong one; hand-rolled proxies around listeners that only extend Object.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/c9e99788106e758d. Report an issue: GitHub.