hibernate/hibernate-orm · error · HibernateException

Could not instantiate event listener '{}'

Error message

Could not instantiate event listener '{}'

What it means

Hibernate throws this while a SessionFactory initializes, when it cannot reflectively instantiate a custom event listener. Listeners are registered via properties named hibernate.event.listener.<event-type> (e.g. hibernate.event.listener.load) whose value is a comma-separated list of fully-qualified class names; MetadataImpl.initSessionFactory loads each class with ClassLoaderService and calls its no-arg constructor. Any failure (class not found, no public no-arg constructor, abstract class, or a constructor that throws) is wrapped in this HibernateException with the original cause attached.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java:528

			EventType<T> eventType) {
		final var eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType );
		for ( String listenerImpl : splitAtCommas( listeners ) ) {
			final var listener = instantiate( listenerImpl, classLoaderService );
			final var baseListenerInterface = eventType.baseListenerInterface();
			if ( !baseListenerInterface.isInstance( listener ) ) {
				throw new HibernateException( "Event listener '" + listenerImpl
						+ "' must implement '" + baseListenerInterface.getName() + "'");
			}
			eventListenerGroup.appendListener( baseListenerInterface.cast( listener ) );
		}
	}

	private static Object instantiate(String listenerImpl, ClassLoaderService classLoaderService) {
		try {
			return classLoaderService.classForName( listenerImpl ).newInstance();
		}
		catch (Exception e) {
			throw new HibernateException( "Could not instantiate event listener '" + listenerImpl + "'", e );
		}
	}

	@Override
	public void visitRegisteredComponents(Consumer<Component> consumer) {
		composites.forEach( consumer );
	}

	@Override
	public Component getGenericComponent(Class<?> componentClass) {
		return genericComponentsMap.get( componentClass );
	}

	@Override
	public DiscriminatorType<?> resolveEmbeddableDiscriminatorType(
			Class<?> embeddableClass,
			Supplier<DiscriminatorType<?>> supplier) {
		return embeddableDiscriminatorTypesMap.computeIfAbsent( embeddableClass, k -> supplier.get() );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Check the exact fully-qualified class name in the hibernate.event.listener.<event-type> property and that the class is on the runtime classpath
  2. Give the listener a public no-argument constructor (classForName(...).newInstance() requires it)
  3. Unwrap and inspect the nested cause: ClassNotFoundException means classpath/typo, InvocationTargetException means the constructor itself threw
  4. If the listener needs dependencies, use a no-arg constructor with lazy lookup or register the listener programmatically via EventListenerRegistry instead of the property
  5. Verify in a scratch test: Class.forName(name).getConstructor().newInstance()

Example fix

// before: hibernate.cfg.xml property
// hibernate.event.listener.load = com.acme.AuditLoadListener
// where AuditLoadListener only defines AuditLoadListener(DataSource ds)

// after: add a public no-arg constructor to the listener
public AuditLoadListener() {
    this.dataSource = DataSourceHolder.lookup(); // lazy, no injection needed
}
public AuditLoadListener(DataSource ds) {
    this.dataSource = ds;
}
Defensive patterns

Strategy: validation

Validate before calling

// before building the SessionFactory, check every configured listener
static void checkEventListeners(Properties props) throws Exception {
    for (String name : props.stringPropertyNames()) {
        if (!name.startsWith("hibernate.event.listener.")) continue;
        for (String cls : props.getProperty(name).split(",")) {
            Class<?> c = Class.forName(cls.trim());
            if (c.isInterface() || Modifier.isAbstract(c.getModifiers()))
                throw new IllegalStateException("Listener is abstract/interface: " + cls);
            c.getConstructor(); // fails fast without public no-arg ctor
        }
    }
}

Type guard

static boolean isInstantiableListener(String fqcn) {
    try {
        Class<?> c = Class.forName(fqcn);
        return !c.isInterface() && !Modifier.isAbstract(c.getModifiers())
            && java.lang.reflect.Modifier.isPublic(c.getConstructor().getModifiers());
    } catch (ReflectiveOperationException e) { return false; }
}

Try / catch

try {
    SessionFactory sf = metadata.buildSessionFactory();
} catch (HibernateException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Could not instantiate event listener")) {
        Throwable cause = e.getCause();
        // ClassNotFoundException -> classpath/typo; InvocationTargetException -> ctor bug
        log.error("Bad event listener config: {}", cause, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: SessionFactory bootstrap scans all settings starting with 'hibernate.event.listener.' and calls classLoaderService.classForName(listenerImpl).newInstance(); the error fires when the class is missing from the classpath, is abstract or an interface, has no accessible no-arg constructor, or its constructor throws an exception.

Common situations: Listener class renamed/moved during an upgrade but the property still holds the old name; listener lives in a module not deployed with the persistence unit; constructor expects injected dependencies and throws NPE; typo in the class name; property copied from another application where the class exists.

Related errors


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