grpc/grpc-java · error · IOException

SocketFactory did not produce an SSLSocket

Error message

SocketFactory ${socketFactory} did not produce an SSLSocket: ${s.getClass()}

What it means

ClientCertRequestingSocketFactory (and related wrapper) wraps a base SSLSocketFactory but requires the sockets it produces to actually be SSLSocket instances so client-auth and protocol settings can be applied. If the configured socket factory yields a plain socket, apply() throws IOException stating the factory did not produce an SSLSocket.

Solutions

  1. Fix the custom SocketFactory so every createSocket overload returns an SSLSocket (typically obtained from an SSLContext's SSLSocketFactory)
  2. Alternatively use TlsServerCredentials.keyManager/trustManager and let gRPC build the SSL socket itself
  3. Log/inspect which factory instance is printed in the message to identify the faulty factory

Example fix

// before
return new Socket();
// after
return sslContext.getSocketFactory().createSocket(host, port);
Defensive patterns

Strategy: validation

Validate before calling

Socket test = mySocketFactory.createSocket();
if (!(test instanceof SSLSocket)) throw new IllegalStateException("Factory must return SSLSocket");

Type guard

function returnsSslSocket(f: javax.net.SocketFactory, s: Socket): boolean { return s instanceof javax.net.ssl.SSLSocket; }

Try / catch

try { server.start(); }
catch (IOException e) {
  if (e.getMessage().startsWith("SocketFactory ")) { /* fix custom factory to return SSLSocket */ }
}

Prevention

When it happens

Trigger: A custom javax.net.SocketFactory supplied via TlsServerCredentials.customSSLSocketFactory... style configuration returns a non-SSL Socket when createSocket is called during connection setup.

Common situations: Misconfigured custom socket factories, factories that delegate to the default factory but return a wrapped/plain socket, mocking or subclassing mistakes in test setups.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/366a874eb4a12ebc. Report an issue: GitHub.

Appendix: source

Thrown at okhttp/src/main/java/io/grpc/okhttp/OkHttpServerBuilder.java:533

    public static HandshakerSocketFactoryResult factory(HandshakerSocketFactory factory) {
      return new HandshakerSocketFactoryResult(
          Preconditions.checkNotNull(factory, "factory"), null);
    }
  }

  static final class ClientCertRequestingSocketFactory extends SSLSocketFactory {
    private final SSLSocketFactory socketFactory;
    private final boolean required;

    public ClientCertRequestingSocketFactory(SSLSocketFactory socketFactory, boolean required) {
      this.socketFactory = Preconditions.checkNotNull(socketFactory, "socketFactory");
      this.required = required;
    }

    private Socket apply(Socket s) throws IOException {
      if (!(s instanceof SSLSocket)) {
        throw new IOException(
            "SocketFactory " + socketFactory + " did not produce an SSLSocket: " + s.getClass());
      }
      SSLSocket sslSocket = (SSLSocket) s;
      if (required) {
        sslSocket.setNeedClientAuth(true);
      } else {
        sslSocket.setWantClientAuth(true);
      }
      return sslSocket;
    }

    @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose)
        throws IOException {
      return apply(socketFactory.createSocket(s, host, port, autoClose));
    }

    @Override public Socket createSocket(String host, int port) throws IOException {
      return apply(socketFactory.createSocket(host, port));

View on GitHub (pinned to 64daddc1f3)