apple/pkl · error · SSLHandshakeException

errorSslHandshake

errorSslHandshake

Error message

errorSslHandshake: ${host}: ${reason}

What it means

JdkHttpClient.send catches SSLHandshakeException and rethrows an SSLHandshakeException with code 'errorSslHandshake' including the host and the root cause reason. It means the TLS handshake with the server failed — typically certificate trust, protocol, or cipher problems.

Solutions

  1. Add the server's (or corporate CA's) certificate to the evaluator's trusted certificates via PklEvaluatorSettings certificateFiles/certificateBytes
  2. Read the 'reason' in the message: fix expired/mismatched certificates on the server if you control it
  3. If behind a TLS-intercepting proxy, import the proxy's root CA into the trust settings
  4. Check TLS version compatibility (force TLS 1.2/1.3 as needed)

Example fix

// before: evaluator without custom CA, self-signed internal host fails
var eval = EvaluatorBuilder.preconfigured().build();
// after
var settings = new PklEvaluatorSettings();
settings.setCertificateFiles(List.of(Path.of("/etc/certs/internal-ca.pem")));
var eval = EvaluatorBuilder.preconfigured().applyFromSettings(settings).build();
Defensive patterns

Strategy: fallback

Validate before calling

// verify the server certificate is trusted before evaluating
Process p = new ProcessBuilder("openssl", "s_client", "-connect", host + ":443", "-servername", host).start();
// inspect the presented chain; ensure the CA is in your evaluator's certificateFiles

Try / catch

try {
  return client.send(request, handler);
} catch (SSLHandshakeException e) {
  if (e.getMessage().startsWith("errorSslHandshake")) {
    // rebuild client with the CA from the message's reason (e.g. add CA cert to settings) and retry once
  }
}

Prevention

When it happens

Trigger: Any HTTPS request where the TLS handshake fails: self-signed or unknown CA certificate, expired server certificate, hostname mismatch, TLS version/cipher incompatibility, corporate TLS-intercepting proxy.

Common situations: Internal CA not in the trust store, MITM proxies at work, dev servers with self-signed certs, custom certificates not passed via evaluator settings (certificateFiles/certificateBytes).

Understand the failure class

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/090fb7b6d0a39e46. Report an issue: GitHub.

Appendix: source

Thrown at pkl-core/src/main/java/org/pkl/core/http/JdkHttpClient.java:103

            .proxy(proxySelector)
            .followRedirects(Redirect.NEVER)
            .build();
  }

  @Override
  public <T> HttpResponse<T> send(
      HttpRequest request,
      BodyHandler<T> responseBodyHandler,
      HttpRequestChecker httpRequestChecker)
      throws IOException {
    try {
      return underlying.send(request, responseBodyHandler);
    } catch (ConnectException e) {
      // original exception has no message
      throw new ConnectException(
          ErrorMessages.create("errorConnectingToHost", request.uri().getHost()));
    } catch (SSLHandshakeException e) {
      throw new SSLHandshakeException(
          ErrorMessages.create(
              "errorSslHandshake", request.uri().getHost(), Exceptions.getRootReason(e)));
    } catch (SSLException e) {
      throw new SSLException(Exceptions.getRootReason(e));
    } catch (InterruptedException e) {
      // next best thing after letting (checked) InterruptedException bubble up
      Thread.currentThread().interrupt();
      throw new IOException(e);
    }
  }

  @Override
  public void close() {
    try {
      closeMethod.invoke(underlying);
    } catch (RuntimeException | Error e) {
      throw e;
    } catch (Throwable t) {

View on GitHub (pinned to f3efcbfc9b)