quarkusio/quarkus · error · AmbiguousResolutionException

multiple beans with type + type.getName() + found for TLS co

Error message

multiple beans with type + type.getName() + found for TLS configuration + bucketName

What it means

TLS keystore/truststore providers are resolved from the CDI container by type plus Identifier qualifier (the TLS configuration name, or @Default for 'default'). If more than one bean of the requested provider type (e.g. KeystoreProvider/TrustStoreProvider) matches the same configuration name, the resolution is ambiguous and Arc cannot choose, so lookupProvider throws AmbiguousResolutionException.

Source

Thrown at extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/CertificateRecorder.java:250

            @Override
            public TlsConfigurationRegistry get() {
                return CertificateRecorder.this;
            }
        };
    }

    public void register(String name, Supplier<TlsConfiguration> supplier) {
        register(name, supplier.get());
    }

    static <T> InstanceHandle<T> lookupProvider(Class<T> type, String bucketName) {
        var container = Arc.container();
        var qualifier = TlsConfig.DEFAULT_NAME.equals(bucketName)
                ? Default.Literal.INSTANCE
                : Identifier.Literal.of(bucketName);
        var instances = container.listAll(type, qualifier);
        if (instances.size() > 1) {
            throw new AmbiguousResolutionException(
                    "multiple beans with type " + type.getName() + " found for TLS configuration " + bucketName);
        }
        if (instances.isEmpty()) {
            return new InstanceHandle<T>() {
                @Override
                public T get() {
                    return null;
                }
            };
        }
        return instances.get(0);
    }

    static <T> InstanceHandle<T> lookupFactory(Class<T> type, String typeName) {
        var container = Arc.container();
        var qualifier = Identifier.Literal.of(typeName);
        var instances = container.listAll(type, qualifier);
        if (instances.size() > 1) {

View on GitHub (pinned to e1c734241f)

Solutions

  1. Make the bean unique: remove or de-duplicate one of the conflicting provider beans so only one remains per type + identifier.
  2. Change the @Identifier qualifier on your custom provider to a distinct TLS configuration name and reference that name via tls.*-tls-configuration-name.
  3. If you must ship a replacement for the default, mark the built-in bean unremovable duplicates carefully — instead exclude the conflicting provider (e.g. via @ExcludeBean or removing the library dependency).

Example fix

// before
@ApplicationScoped
@Identifier("default")
class MyKeyStoreProvider implements KeystoreProvider { ... }
// after
@ApplicationScoped
@Identifier("my-app-ssl")
class MyKeyStoreProvider implements KeystoreProvider { ... }
// and set quarkus.tls.key-store-provider / tls.my-app-ssl references accordingly
Defensive patterns

Strategy: validation

Validate before calling

List<InstanceHandle<KeystoreProvider>> existing = Arc.container()
    .listAll(KeystoreProvider.class, Identifier.Literal.of("my-app-ssl"));
if (existing.size() > 1) {
    throw new IllegalStateException("Duplicate KeystoreProvider beans for identifier 'my-app-ssl'");
}

Type guard

boolean hasUniqueProvider(Class<?> type, String bucketName) {
    var qualifier = TlsConfig.DEFAULT_NAME.equals(bucketName)
        ? Default.Literal.INSTANCE : Identifier.Literal.of(bucketName);
    return Arc.container().listAll(type, qualifier).size() == 1;
}

Try / catch

try {
    TlsConfiguration cfg = registry.get("my-app-ssl");
    // use cfg
} catch (AmbiguousResolutionException e) {
    log.error("Multiple provider beans for this TLS config; check @Identifier qualifiers", e);
}

Prevention

When it happens

Trigger: Two beans implementing the same provider type annotated @Identifier("<name>") (or both @Default for the default bucket) exist in the container and getKeyStore/getTrustStore calls lookupProvider for that name.

Common situations: Registering a custom KeystoreProvider/TrustStoreProvider with @Identifier("default") while the built-in ones are also active; accidentally duplicating a provider bean in a library and an application; renaming a configuration bucket so two providers now share one identifier.

Understand the failure class

Related errors


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