quarkusio/quarkus · error · IllegalStateException

Multiple HealthCheckResponseProvider implementations found:

Error message

Multiple HealthCheckResponseProvider implementations found: %s

What it means

The health extension build step requires exactly one HealthCheckResponseProvider implementation discovered through ServiceLoader. When more than one implementation is registered in META-INF/services/org.eclipse.microprofile.health.HealthCheckResponseProvider across the classpath, the build fails with this IllegalStateException listing all found providers, since the choice would be ambiguous.

Source

Thrown at extensions/smallrye-health/deployment/src/main/java/io/quarkus/smallrye/health/deployment/SmallRyeHealthProcessor.java:187

        beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(HEALTH_GROUPS, BuiltinScope.SINGLETON.getName()));
        beanDefiningAnnotation.produce(new BeanDefiningAnnotationBuildItem(WELLNESS, BuiltinScope.SINGLETON.getName()));

        // Add additional beans
        additionalBean.produce(new AdditionalBeanBuildItem(QuarkusAsyncHealthCheckFactory.class));
        excludedTypes.produce(new ExcludedTypeBuildItem(AsyncHealthCheckFactory.class.getName()));
        additionalBean.produce(new AdditionalBeanBuildItem(SmallRyeHealthReporter.class));

        // Make ArC discover @HealthGroup as a qualifier
        additionalBean.produce(new AdditionalBeanBuildItem(HealthGroup.class));

        // Discover and register the HealthCheckResponseProvider
        Set<String> providers = ServiceUtil.classNamesNamedIn(getClass().getClassLoader(),
                "META-INF/services/" + HealthCheckResponseProvider.class.getName());

        if (providers.isEmpty()) {
            throw new IllegalStateException("No HealthCheckResponseProvider implementation found.");
        } else if (providers.size() > 1) {
            throw new IllegalStateException(
                    String.format("Multiple HealthCheckResponseProvider implementations found: %s", providers));
        }

        final String provider = providers.iterator().next();
        final Class<? extends HealthCheckResponseProvider> responseProvider = (Class<? extends HealthCheckResponseProvider>) Class
                .forName(provider, true, Thread.currentThread().getContextClassLoader());
        recorder.registerHealthCheckResponseProvider(responseProvider);
    }

    @BuildStep
    public void defineHealthRoutes(BuildProducer<RouteBuildItem> routes,
            BeanArchiveIndexBuildItem beanArchiveIndex,
            NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem,
            SmallRyeHealthBuildTimeConfig healthConfig) {
        IndexView index = beanArchiveIndex.getIndex();

        // log a warning if users try to use MP Health annotations with JAX-RS @Path
        warnIfJaxRsPathUsed(index, LIVENESS);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Run mvn dependency:tree, find duplicates of smallrye-health, and exclude the unwanted copy so exactly one provider remains
  2. Align SmallRye Health versions via the Quarkus BOM and remove manually declared smallrye-health artifacts
  3. Remove any additional MP Health implementation dependency that ships its own provider

Example fix

// before — two sources of the provider
<dependency>io.smallrye:smallrye-health:3.1.0</dependency>
<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-smallrye-health</artifactId>
</dependency>

// after — only the extension, versions managed by the BOM
<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-smallrye-health</artifactId>
</dependency>
Defensive patterns

Strategy: validation

Validate before calling

Set<String> providers = ServiceUtil.classNamesNamedIn(getClass().getClassLoader(),
        "META-INF/services/org.eclipse.microprofile.health.HealthCheckResponseProvider");
if (providers.size() > 1) {
    throw new IllegalStateException("Exactly one HealthCheckResponseProvider allowed, found: " + providers);
}

Try / catch

try {
    quarkusBuild();
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("Multiple HealthCheckResponseProvider")) {
        throw new IllegalStateException("Deduplicate smallrye-health on the classpath: " + e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Two or more jars each ship META-INF/services/org.eclipse.microprofile.health.HealthCheckResponseProvider — e.g. both the smallrye-health CDI provider and another implementation (or two copies/versions of smallrye-health) on the build classpath.

Common situations: Mixed SmallRye Health versions in the dependency tree; an app depending on both quarkus-smallrye-health and raw smallrye-health artifacts from different releases; shaded jars that duplicate the services file; adding a second MP Health implementation for testing.

Related errors


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