{"record":{"id":"c9e99788106e758d","repo":"hibernate/hibernate-orm","slug":"listener-did-not-implement-expected-interface","errorCode":null,"errorMessage":"Listener did not implement expected interface [","messagePattern":"Listener did not implement expected interface \\[","errorType":"exception","errorClass":"EventListenerRegistrationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java","lineNumber":361,"sourceCode":"\t\t// we did not find any match, add it\n\t\tcheckAgainstBaseInterface( listener );\n\t\tadditionHandler.accept( listener );\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\t@AllowReflection // Possible array types are registered in org.hibernate.graalvm.internal.StaticClassLists.typesNeedingArrayCopy\n\t@Nonnull\n\tprivate T[] createListenerArrayForWrite(int len) {\n\t\treturn (T[]) Array.newInstance( eventType.baseListenerInterface(), len );\n\t}\n\n\tprivate void prepareListener(@Nonnull T listener) {\n\t\tcheckAgainstBaseInterface( listener );\n\t}\n\n\tprivate void checkAgainstBaseInterface(@Nonnull T listener) {\n\t\tif ( !eventType.baseListenerInterface().isInstance( listener ) ) {\n\t\t\tthrow new EventListenerRegistrationException( \"Listener did not implement expected interface [\"\n\t\t\t\t\t+ eventType.baseListenerInterface().getName() + \"]\" );\n\t\t}\n\t}\n\n\t/**\n\t * Implementation note: should be final for performance reasons.\n\t * @deprecated this is not the most efficient way for iterating the event listeners.\n\t * See {@link #fireEventOnEachListener(Object, BiConsumer)} and co. for better alternatives.\n\t */\n\t@Override\n\t@Deprecated\n\tpublic final @Nonnull Iterable<T> listeners() {\n\t\treturn listenersAsList;\n\t}\n}\n","sourceCodeStart":343,"sourceCodeEnd":377,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java#L343-L377","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Register each listener only on the EventListenerGroup whose EventType's baseListenerInterface it implements (PersistEventListener -> EventType.PERSIST, PostLoadEventListener -> EventType.POST_LOAD, etc.)","Keep EventListenerGroup<T> generic in your code — avoid raw types so mismatches fail at compile time","Make proxy/decorator wrappers implement the same listener interface as the wrapped instance (or skip wrapping)"],"exampleFix":"// before\nEventListenerGroup raw = registry.getEventListenerGroup(EventType.POST_INSERT);\nraw.appendListeners(new MyPostLoadListener()); // raw type hides mismatch -> Listener did not implement expected interface\n\n// after\nEventListenerGroup<PostInsertEventListener> g = registry.getEventListenerGroup(EventType.POST_INSERT);\ng.appendListeners(new MyPostInsertListener()); // compiles only when types line up","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"boolean implementsBase(EventType<?> type, Object listener) {\n    return type.baseListenerInterface().isInstance(listener);\n}\n// EventType#baseListenerInterface is public; call before appendListeners","tryCatchPattern":"try {\n    group.appendListeners(listener);\n} catch (EventListenerRegistrationException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Listener did not implement\")) {\n        // wrong group or wrong listener class — fix the EventType/listener pairing\n    }\n    throw e;\n}","preventionTips":["Always type EventListenerGroup<T> with the listener interface — never raw types","Pair listener registrations by interface family (one constant per listener class) in a helper method","Make wrapper/proxy listeners implement the same interface as the wrapped target"],"tags":["hibernate","event-listener","type-mismatch","raw-types","registration"],"backgroundTag":"listener-interface-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}