apache/pulsar · error · IllegalArgumentException

No java.security.Provider named '${name}' could be resolved

Error message

No java.security.Provider named '${name}' could be resolved via Security.getProvider(...) or via ServiceLoader (META-INF/services/java.security.Provider) on the application class loader. Ensure the provider is on the classpath and registered — a JSSE (SSLContext) provider such as BCJSSE for jsseProvider (which additionally requires the bctls jar on the classpath), or a JCA (KeyStore/CertificateFactory) provider such as BCFIPS for jcaProvider.

What it means

JcaProviders.resolveNamedProvider(name) resolves a named java.security.Provider first via Security.getProvider(name), then via ServiceLoader on META-INF/services/java.security.Provider, and finally via known BouncyCastle aliases. If nothing resolves, it throws IllegalArgumentException — a misconfigured provider must fail loudly rather than silently falling back to the default.

Source

Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/tls/JcaProviders.java:433

                                + "named JCA provider");
                continue;
            }
            if (name.equals(provider.getName())) {
                log.debug().attr("provider", name).log("Resolved JCA provider via ServiceLoader");
                return provider;
            }
        }
        // 3. BouncyCastle's JSSE provider is invisible to both steps above until someone registers it —
        // bctls ships no services entry — so register it from the classpath on demand when it is the name
        // being pinned. See bouncyCastleJsseProvider() for why it cannot just be default-constructed.
        if (BC_JSSE.equals(name)) {
            Optional<ResolvedBouncyCastleProvider> jsse = bouncyCastleJsseProvider();
            if (jsse.isPresent()) {
                return jsse.get().provider();
            }
        }
        // 4. Fail loudly — a misconfigured provider must not silently default.
        throw new IllegalArgumentException("No java.security.Provider named '" + name + "' could be resolved via "
                + "Security.getProvider(...) or via ServiceLoader (META-INF/services/java.security.Provider) on the "
                + "application class loader. Ensure the provider is on the classpath and registered — a JSSE "
                + "(SSLContext) provider such as BCJSSE for jsseProvider (which additionally requires the bctls jar "
                + "on the classpath), or a JCA (KeyStore/CertificateFactory) "
                + "provider such as BCFIPS for jcaProvider.");
    }

    /**
     * Resolve a security {@link Provider} by name, falling back to the default {@code TLS}
     * {@code SSLContext} provider when the name is blank or unknown.
     */
    static Provider resolveProvider(String providerName) throws NoSuchAlgorithmException {
        Provider provider = null;
        if (!StringUtils.isEmpty(providerName)) {
            provider = Security.getProvider(providerName);
        }

        if (provider == null) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Add the provider jar to the classpath (bc-fips for BCFIPS; bcpkix/bctls for BCJSSE)
  2. Register it programmatically with Security.addProvider(new BouncyCastleFipsProvider()) or in java.security config
  3. Correct the provider name spelling in the configuration to match Provider.getName()
  4. Verify ServiceLoader entries survive shading/build repackaging

Example fix

// before (config)
tlsJsseProviderName=BCJSSE   // bctls jar missing
// after
// add bctls + bc-fips jars to classpath, then:
Security.addProvider(new org.bouncycastle.jsse.provider.BouncyCastleJsseProvider());
tlsJsseProviderName=BCJSSE
Defensive patterns

Strategy: validation

Validate before calling

String name = "BCFIPS";
Provider p = Security.getProvider(name);
if (p == null) {
    p = ServiceLoader.load(java.security.Provider.class).stream()
        .map(Provider::getName).filter(name::equals).findFirst().orElse(null);
}
if (p == null) throw new IllegalStateException("Provider " + name + " not on classpath/registered");

Type guard

java.util.Optional<Provider> findProvider(String name) { Provider p = Security.getProvider(name); return p != null ? java.util.Optional.of(p) : ServiceLoader.load(java.security.Provider.class).stream().filter(x -> x.getName().equals(name)).findFirst(); }

Try / catch

try { Provider p = JcaProviders.resolveNamedProvider(name); } catch (IllegalArgumentException e) { log.error("TLS provider '{}' unresolved — check classpath and Security.addProvider: {}", name, e.getMessage()); throw e; }

Prevention

When it happens

Trigger: Configuring a provider name (e.g. jsseProvider=BCJSSE or jcaProvider=BCFIPS) when: the jar is not on the classpath; the provider was never registered via Security.addProvider / security properties; the name is misspelled; or for BCJSSE the bctls jar is missing so the SSLContext provider cannot be found.

Common situations: FIPS-mode broker/client startup with tls provider settings pointing at BouncyCastle that isn't packaged; typos in provider names in pulsar config files; fat-jar shading dropping META-INF/services entries.

Understand the failure class

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/4c7c3116174301a4. Report an issue: GitHub.