pinpoint-apm/pinpoint · error · SSLException

cipherSuites must not be empty

Error message

cipherSuites must not be empty

What it means

SslContextFactory.assertValidCipherSuite builds a netty SslContext and then checks sslContext.cipherSuites(); if the resulting context advertises no cipher suites, it throws SSLException("cipherSuites must not be empty"). A TLS context with zero ciphers can never complete a handshake, so the factory refuses to return it during forServer.

Source

Thrown at grpc/src/main/java/com/navercorp/pinpoint/grpc/security/SslContextFactory.java:116

    }


    private SslContext createSslContext(SslContextBuilder sslContextBuilder, SslProvider sslProvider) throws SSLException {
        sslContextBuilder.sslProvider(sslProvider);

        sslContextBuilder.protocols(SecurityConstants.DEFAULT_SUPPORT_PROTOCOLS.toArray(new String[0]));
        sslContextBuilder.ciphers(SecurityConstants.DEFAULT_SUPPORT_CIPHER_SUITE, SupportedCipherSuiteFilter.INSTANCE);

        SslContextBuilder configure = GrpcSslContexts.configure(sslContextBuilder, sslProvider);
        return configure.build();
    }

    private void assertValidCipherSuite(SslContext sslContext) throws SSLException {
        Objects.requireNonNull(sslContext, "sslContext must not be null");

        List<String> supportedCipherSuiteList = sslContext.cipherSuites();
        if (CollectionUtils.isEmpty(supportedCipherSuiteList)) {
            throw new SSLException("cipherSuites must not be empty");
        }

        for (String cipherSuite : supportedCipherSuiteList) {
            if (SecurityConstants.BAD_CIPHER_SUITE_LIST.contains(cipherSuite)) {
                throw new SSLException(cipherSuite + " is not safe. Please check this url.(https://httpwg.org/specs/rfc7540.html#BadCipherSuites)");
            }
        }

        LOGGER.info("Support cipher list : {} {}", sslContext, supportedCipherSuiteList);
    }

    SslProvider getSslProvider(String providerType) throws SSLException {
        if (StringUtils.isEmpty(providerType)) {
            return SslProvider.OPENSSL;
        }

        if (SslProvider.OPENSSL.name().equalsIgnoreCase(providerType)) {
            return SslProvider.OPENSSL;

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Inspect the JVM's crypto policy (java.security, crypto.policy) and restore/enable TLS cipher availability.
  2. Try the other SslProvider (e.g. switch between JDK and OPENSSL) via the SSL provider configuration.
  3. Update to a JCE/netty version whose supported cipher list is non-empty for your configured protocols.
  4. Verify enabled TLS protocol settings (e.g. TLSv1.2) actually have ciphers available in your environment.

Example fix

// before (empty cipher env, JDK provider)
providerType=JDK
// after
providerType=OPENSSL
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check: list ciphers the JVM can actually use
for (String c : javax.net.ssl.SSLContext.getDefault().getSupportedSSLParameters().getCipherSuites()) {
    LOG.debug("JVM cipher: {}", c);
}

Try / catch

try {
    sslContext = SslContextFactory.forServer(...);
} catch (SSLException e) {
    LOG.error("SSL context invalid: {}", e.getMessage());
    throw new IllegalStateException("TLS setup failed, check crypto policy/provider", e);
}

Prevention

When it happens

Trigger: Calling SslContextFactory.forServer with an SslProvider/protocol configuration (e.g. JDK provider with restricted protocols, or FIPS/restricted JCE) that yields an SslContext whose cipherSuites() list is empty.

Common situations: Running on a JVM with a restricted or FIPS crypto policy that disables all default TLS ciphers; misconfigured enabled protocols that exclude every cipher; unusual netty-transport-native builds where no cipher provider is available.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/1133e2b0189dd0c5. Report an issue: GitHub.