quarkusio/quarkus · error · IllegalStateException

Multiple instances of %1$s were found for Hibernate Search i

Error message

Multiple instances of %1$s were found for Hibernate Search index %2$s in persistence unit %3$s. At most one instance can be assigned to each index. Instances found: %4$s

What it means

Quarkus's Hibernate Search ORM Elasticsearch extension resolves exactly one CDI bean for a given Hibernate Search index (e.g. an ElasticsearchIndexManager or similar bean type) within a persistence unit. When CDI's InjectableInstance is ambiguous — more than one bean matches the required type and qualifiers for that index — the extension cannot pick one and throws this IllegalStateException from HibernateSearchBeanUtil.singleExtensionBeanReferenceFor. The error lists the bean classes that were found so you can remove or disambiguate them.

Source

Thrown at extensions/hibernate-search-orm-elasticsearch/runtime/src/main/java/io/quarkus/hibernate/search/orm/elasticsearch/runtime/bean/HibernateSearchBeanUtil.java:34

public final class HibernateSearchBeanUtil {

    private HibernateSearchBeanUtil() {
    }

    public static <T> Optional<BeanReference<T>> singleExtensionBeanReferenceFor(Optional<String> override, Class<T> beanType,
            String persistenceUnitName, String backendName, String indexName) {
        return override.map(string -> BeanReference.parse(beanType, string))
                .or(() -> singleExtensionBeanReferenceFor(beanType, persistenceUnitName, backendName, indexName));
    }

    private static <T> Optional<BeanReference<T>> singleExtensionBeanReferenceFor(Class<T> beanType,
            String persistenceUnitName, String backendName, String indexName) {
        InjectableInstance<T> instance = extensionInstanceFor(beanType, persistenceUnitName, backendName, indexName);
        if (instance.isAmbiguous()) {
            List<String> ambiguousClassNames = instance.handlesStream().map(h -> h.getBean().getBeanClass().getCanonicalName())
                    .toList();
            if (indexName != null) {
                throw new IllegalStateException(String.format(Locale.ROOT,
                        "Multiple instances of %1$s were found for Hibernate Search index %2$s in persistence unit %3$s."
                                + " At most one instance can be assigned to each index. Instances found: %4$s",
                        beanType.getSimpleName(), indexName, persistenceUnitName, ambiguousClassNames));
            } else if (backendName != null) {
                throw new IllegalStateException(String.format(Locale.ROOT,
                        "Multiple instances of %1$s were found for Hibernate Search backend %2$s in persistence unit %3$s."
                                + " At most one instance can be assigned to each backend. Instances found: %4$s",
                        beanType.getSimpleName(), backendName, persistenceUnitName, ambiguousClassNames));
            } else {
                throw new IllegalStateException(String.format(Locale.ROOT,
                        "Multiple instances of %1$s were found for Hibernate Search in persistence unit %2$s."
                                + " At most one instance can be assigned to each persistence unit. Instances found: %3$s",
                        beanType.getSimpleName(), persistenceUnitName, ambiguousClassNames));
            }
        }
        return instance.isResolvable() ? Optional.of(new ArcBeanReference<>(instance.getHandle().getBean())) : Optional.empty();
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Identify the duplicate classes listed in the message ('Instances found: [A, B]') and delete or de-register one of them.
  2. Make the unwanted bean not match the index by changing/removing its @SearchExtension qualifier (e.g. different backend/index name) or annotate it with @Alternative/@Priority so only one is selected.
  3. If the duplicate comes from a library/test fixture, exclude it via @QuarkusTestProfile or a CDI @Exclude/veto so it is not discovered in production.
  4. Ensure you are not accidentally producing the same bean twice (e.g. a @Produces method plus a class-level @SearchExtension on the same type).

Example fix

// before: two beans for the same index
@SearchExtension(backend = "default", index = "Books")
public class MyBridgeA implements PropertyBridge<Book> { ... }
@SearchExtension(backend = "default", index = "Books")
public class MyBridgeB implements PropertyBridge<Book> { ... }

// after: only one bean assigned to the index
@SearchExtension(backend = "default", index = "Books")
public class MyBridgeA implements PropertyBridge<Book> { ... }
// MyBridgeB removed, or given a different index/backend qualifier
Defensive patterns

Strategy: validation

Validate before calling

// Before startup, assert exactly one bean targets each index:
Set<String> indexBeans = Arc.container().instance(Object.class)
    .selectWithQualifier(new SearchExtensionQualifier("default", "Books"))
    .handlesStream().map(h -> h.getBean().getBeanClass().getName())
    .collect(Collectors.toSet());
if (indexBeans.size() > 1) {
    throw new IllegalStateException("Duplicate index beans: " + indexBeans);
}

Try / catch

try {
    hibernateSearchBooter.start();
} catch (IllegalStateException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Multiple instances of")) {
        LOGGER.error("Duplicate @SearchExtension beans; keep one per index: " + e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling singleExtensionBeanReferenceFor with a non-null indexName where extensionInstanceFor(...) resolves an InjectableInstance whose isAmbiguous() is true — i.e. two or more CDI beans of the requested type (with the same qualifiers) are visible in the persistence unit and assigned to the same index. Typical API path: application code or internal boot code requesting a single bean reference via HibernateSearchBeanUtil during Hibernate Search initialization.

Common situations: Declaring two custom beans (e.g. two @SearchExtension-annotated beans such as two PropertyBridge or EntityLoadingContext beans of the same type) targeting the same named index; accidentally registering the same bean in both application and a test @Produces; copying a bean class into two packages so both are discovered; using @DefaultBean plus your own override without correct qualifiers for the index.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/65379a0f7f988769. Report an issue: GitHub.