grpc/grpc-java · error · IOException

SocketFactory ${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.

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)

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.