Homebrew/homebrew-core · error · RuntimeException
Failed to initialize non-FIPS provider
Error message
Failed to initialize non-FIPS provider
What it means
RuntimeException thrown by the patched org.sonatype.nexus.crypto.internal.CryptoHelperImpl.loadNonFipsProvider() (patch hunk carried at Formula/n/nexus.rb:200) when it cannot reflectively load and instantiate org.bouncycastle.jce.provider.BouncyCastleProvider. The provider is deliberately loaded through an isolated URLClassLoader (bcprov + bcutil only, parent=null) so that bc-fips classes, which share the org.bouncycastle.crypto.* package namespace, cannot interfere. The catch clause covers ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException and IllegalAccessException, so any mismatch between the expected class/jar layout and reality aborts crypto initialization.
Source
Thrown at Formula/n/nexus.rb:200
index dfeb6f0..38e067c 100644
--- a/public/common/components/nexus-crypto/src/main/java/org/sonatype/nexus/crypto/internal/CryptoHelperImpl.java
+++ b/public/common/components/nexus-crypto/src/main/java/org/sonatype/nexus/crypto/internal/CryptoHelperImpl.java
@@ -87,8 +87,25 @@ public class CryptoHelperImpl
}
private static void loadNonFipsProvider() {
- // BouncyCastleProvider must be set as the last provider
- Security.addProvider(new BouncyCastleProvider());
+ try {
+ Class<?> providerClass =
+ getNonFipsClassLoader().loadClass("org.bouncycastle.jce.provider.BouncyCastleProvider");
+ Provider provider = (Provider) providerClass.getConstructor().newInstance();
+ // BouncyCastleProvider must be set as the last provider
+ Security.addProvider(provider);
+ }
+ catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException
+ | InstantiationException | IllegalAccessException e) {
+ throw new RuntimeException("Failed to initialize non-FIPS provider", e);
+ }
+ }
+
+ private static URLClassLoader getNonFipsClassLoader() {
+ // Load bcprov and bcutil in an isolated classloader to prevent bc-fips classes
+ // (which share org.bouncycastle.crypto.* package names) from interfering.
+ URL bcprovUrl = BouncyCastleProvider.class.getProtectionDomain().getCodeSource().getLocation();
+ URL bcutilUrl = org.bouncycastle.util.Arrays.class.getProtectionDomain().getCodeSource().getLocation();
+ return new URLClassLoader(new URL[]{bcprovUrl, bcutilUrl}, null);
}
private static void loadFipsProvider() {
diff --git a/public/common/components/nexus-scheduling/src/main/java/org/sonatype/nexus/scheduling/internal/NoopRecoveryModeService.java b/public/common/components/nexus-scheduling/src/main/java/org/sonatype/nexus/scheduling/internal/NoopRecoveryModeService.java
new file mode 100644
index 0000000..9279594
--- /dev/null
+++ b/public/common/components/nexus-scheduling/src/main/java/org/sonatype/nexus/scheduling/internal/NoopRecoveryModeService.java
@@ -0,0 +1,26 @@View on GitHub (pinned to c0cb250747)
Solutions
- Read the wrapped cause first: log/inspect getCause() (and the nested cause chain) — ClassNotFoundException points to a missing/wrong jar, InvocationTargetException to a constructor failure inside the isolated loader.
- Verify both jars on the runtime classpath actually contain the classes used for code-source discovery: jar tf bcprov-*.jar | grep 'jce/provider/BouncyCastleProvider.class' and jar tf bcutil-*.jar | grep 'util/Arrays.class'; fix the version pair if either is missing.
- If the constructor fails because it references classes outside the two jars, extend the URL[] in getNonFipsClassLoader() with the missing jar(s), or pass a suitable parent classloader instead of null.
- Ensure non-FIPS bcprov/bcutil are present even when bc-fips is deployed, and that the non-FIPS and FIPS artifact versions are the pair Nexus expects; do not shade/relocate the BouncyCastle jars for this deployment.
- Guard getLocation() results for null and fail with an explicit message naming the unresolved class before building the URLClassLoader.
Example fix
// before
private static URLClassLoader getNonFipsClassLoader() {
URL bcprovUrl = BouncyCastleProvider.class.getProtectionDomain().getCodeSource().getLocation();
URL bcutilUrl = org.bouncycastle.util.Arrays.class.getProtectionDomain().getCodeSource().getLocation();
return new URLClassLoader(new URL[]{bcprovUrl, bcutilUrl}, null);
}
// after
private static URLClassLoader getNonFipsClassLoader() {
URL bcprovUrl = requireCodeSource(BouncyCastleProvider.class);
URL bcutilUrl = requireCodeSource(org.bouncycastle.util.Arrays.class);
return new URLClassLoader(new URL[]{bcprovUrl, bcutilUrl}, null);
}
private static URL requireCodeSource(Class<?> clazz) {
URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
if (url == null) {
throw new IllegalStateException("No code source for " + clazz.getName() + "; cannot build isolated BC classloader");
}
return url;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Run before Nexus/crypto init to confirm the isolated BC load will succeed
static boolean nonFipsProviderLoadable() {
URL bcprov = BouncyCastleProvider.class.getProtectionDomain().getCodeSource().getLocation();
URL bcutil = org.bouncycastle.util.Arrays.class.getProtectionDomain().getCodeSource().getLocation();
if (bcprov == null || bcutil == null) return false;
try (URLClassLoader cl = new URLClassLoader(new URL[]{bcprov, bcutil}, null)) {
return cl.loadClass("org.bouncycastle.jce.provider.BouncyCastleProvider").getConstructor() != null;
} catch (ReflectiveOperationException | RuntimeException e) {
return false;
}
} Try / catch
// CryptoHelperImpl init runs in a static block, so catch the wrapper AND the static-init error
try {
// ... trigger crypto helper initialization ...
} catch (ExceptionInInitializerError e) {
Throwable root = unwrap(e.getException()); // walk getCause() chain
if (root instanceof ClassNotFoundException) { /* bcprov/bcutil jar missing or version mismatch */ }
else if (root instanceof InvocationTargetException && root.getCause() != null) { /* provider constructor failed inside isolated loader */ }
throw new IllegalStateException("Non-FIPS BC provider init failed: " + root, root);
} catch (RuntimeException e) { // if not via static init
throw new IllegalStateException("Non-FIPS BC provider init failed: " + unwrap(e), e);
} Prevention
- Pin bcprov and bcutil to a matched version pair in the distribution; never let them drift independently.
- Do not deploy bc-fips and non-FIPS bcprov/bcutil on the same classpath without the isolated-classloader isolation this patch implements.
- After any BouncyCastle upgrade, verify org.bouncycastle.util.Arrays still lives in the jar your code-source discovery assumes (it has moved between bcprov and bcutil across releases).
- Add a startup smoke assertion that Security.getProvider("BC") is non-null after crypto init so silent provider-loss fails loudly.
- Never shade or relocate the BouncyCastle jars in a deployment that relies on code-source-based classloader isolation.
When it happens
Trigger: Calling the static initialization path of CryptoHelperImpl (i.e. Nexus startup / brew install nexus smoke run) when: (a) bcprov or bcutil jar is missing from the classpath so getNonFipsClassLoader() cannot resolve a code-source URL; (b) the BC version's jar split differs (org.bouncycastle.util.Arrays moved between bcprov and bcutil across releases) so the two URLs point at jars that do not contain the expected entries; (c) the provider constructor throws (InvocationTargetException) because it needs a class outside the two-jar, parentless loader; (d) code source getLocation() returns null (module/jrt or custom loader); (e) a bc-fips-only deployment where BouncyCastleProvider (non-FIPS) does not exist at all.
Common situations: Upgrading BouncyCastle versions where classes relocate between bcprov/bcutil; mixing bc-fips artifacts with regular bcprov/bcutil on one classpath (the exact interference this patch isolates against); shaded or relocated uber-jars where code-source URLs no longer match the expected jars; trimmed distributions that drop bcutil; running under a JRE/container where the protection domain reports no location. Note a hard NoClassDefFoundError on the BouncyCastleProvider.class reference itself escapes the catch clause and surfaces raw.
Related errors
AI-assisted analysis of Homebrew/homebrew-core@c0cb250747 (2026-08-21).
Data as JSON: /api/errors/b632f15c77543ed0.
Report an issue: GitHub.