{"id":"cd2fa4b2ae508091","repo":"square/okhttp","slug":"unexpected-default-trust-managers","errorCode":null,"errorMessage":"Unexpected default trust managers:","messagePattern":"Unexpected default trust managers:","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"samples/guide/src/main/java/okhttp3/recipes/CustomCipherSuites.java","lineNumber":93,"sourceCode":"   * Returns the VM's default SSL socket factory, using {@code trustManager} for trusted root\n   * certificates.\n   */\n  private SSLSocketFactory defaultSslSocketFactory(X509TrustManager trustManager)\n      throws NoSuchAlgorithmException, KeyManagementException {\n    SSLContext sslContext = SSLContext.getInstance(\"TLS\");\n    sslContext.init(null, new TrustManager[] { trustManager }, null);\n\n    return sslContext.getSocketFactory();\n  }\n\n  /** Returns a trust manager that trusts the VM's default certificate authorities. */\n  private X509TrustManager defaultTrustManager() throws GeneralSecurityException {\n    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(\n        TrustManagerFactory.getDefaultAlgorithm());\n    trustManagerFactory.init((KeyStore) null);\n    TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();\n    if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {\n      throw new IllegalStateException(\"Unexpected default trust managers:\"\n          + Arrays.toString(trustManagers));\n    }\n    return (X509TrustManager) trustManagers[0];\n  }\n\n  private String[] javaNames(List<CipherSuite> cipherSuites) {\n    String[] result = new String[cipherSuites.size()];\n    for (int i = 0; i < result.length; i++) {\n      result[i] = cipherSuites.get(i).javaName();\n    }\n    return result;\n  }\n\n  /**\n   * An SSL socket factory that forwards all calls to a delegate. Override {@link #configureSocket}\n   * to customize a created socket before it is returned.\n   */\n  static class DelegatingSSLSocketFactory extends SSLSocketFactory {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/square/okhttp/blob/4fc083138014aba3d0078f5c26d1ce84815fa984/samples/guide/src/main/java/okhttp3/recipes/CustomCipherSuites.java#L75-L111","documentation":"Inside defaultTrustManager(), the recipe initialises a TrustManagerFactory with the default algorithm and the JVM's default KeyStore (null), then asserts the result is exactly one TrustManager and that it is an X509TrustManager. If the array length is not 1 or the element is not an X509TrustManager, it throws IllegalStateException(\"Unexpected default trust managers: \" + Arrays.toString(trustManagers)). This is a defensive sanity check about the JRE's security provider configuration, not an OkHttp contract.","triggerScenarios":"Constructing the CustomCipherSuites client. Triggers when the JVM returns multiple TrustManagers (some IBM/Rocket runtimes return one per KeyStore type, or PKIX returns multiple under custom security providers), when a custom java.security file replaces the default provider, or when an agent/monitoring tool injects additional trust managers.","commonSituations":"Running on a non-Oracle/OpenJDK JVM (IBM J9, SapMachine with custom provider) that returns >1 manager; a corporate security agent (e.g. zscaler, fireeye) injecting TLS inspection that alters the default TrustManagerFactory output; an older Android API level where the default algorithm returned a non-X509 manager; testing with a BouncyCastle-first security configuration.","solutions":["Iterate trustManagers and pick the first X509TrustManager instead of asserting exactly one.","Or pass a specific KeyStore (your custom CA bundle) to trustManagerFactory.init(...) so the output is deterministic.","Verify no java.security override or -Djava.security.properties file is reordering providers.","On Android, use AndroidKeyStore explicitly only if intended."],"exampleFix":"// before\nTrustManager[] trustManagers = trustManagerFactory.getTrustManagers();\nif (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {\n  throw new IllegalStateException(\"Unexpected default trust managers:\"\n      + Arrays.toString(trustManagers));\n}\nreturn (X509TrustManager) trustManagers[0];\n\n// after — find the first X509 manager\nfor (TrustManager tm : trustManagers) {\n  if (tm instanceof X509TrustManager) return (X509TrustManager) tm;\n}\nthrow new IllegalStateException(\"No X509TrustManager among defaults: \"\n    + Arrays.toString(trustManagers));","handlingStrategy":"validation","validationCode":"// Robust default-trust-manager selection that tolerates multi-manager JVMs\nTrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\ntmf.init((KeyStore) null);\nX509TrustManager x509 = null;\nfor (TrustManager tm : tmf.getTrustManagers()) {\n  if (tm instanceof X509TrustManager) { x509 = (X509TrustManager) tm; break; }\n}\nif (x509 == null) {\n  throw new GeneralSecurityException(\"No X509TrustManager from \" + Arrays.toString(tmf.getTrustManagers()));\n}","typeGuard":"private static boolean isSingleX509TrustManager(TrustManager[] tms) {\n  return tms != null && tms.length == 1 && tms[0] instanceof X509TrustManager;\n}","tryCatchPattern":"try {\n  X509TrustManager tm = defaultTrustManager();\n} catch (IllegalStateException e) {\n  if (e.getMessage().startsWith(\"Unexpected default trust managers\")) {\n    // fall back: scan for the first X509TrustManager instead of asserting exactly one\n    throw new SecurityConfigurationException(\"Unsupported JVM trust-manager layout\", e);\n  }\n  throw e;\n}","preventionTips":["Do not assume the default TrustManagerFactory yields exactly one manager on every JVM.","Loop over getTrustManagers() and pick the first X509TrustManager.","Check for a custom java.security file or provider-injecting agent when this fails.","On Android, prefer Platform.get() or the system default rather than hand-rolling."],"tags":["okhttp","tls","trust-manager","jvm-config","security-provider","java"],"analyzedSha":"4fc083138014aba3d0078f5c26d1ce84815fa984","analyzedAt":"2026-08-04T19:09:04.639Z","schemaVersion":2}