[BUG] Designer pooled connections defer TLS handshake past the SNI-inspection window, causing intermittent save failures behind SNI-routing proxies

Product: Ignition 8.3.2 (b2025120210)
Designer Launcher: 1.3.8
Client JVM: Azul Systems 17.0.16 (bundled runtime)
Gateway platform: OpenShift 4.20, single gateway pod, exposed via edge-terminated Route (HAProxy)
Severity: Save-to-gateway fails intermittently, work must be retried and can be lost.


Summary

The Designer's Jetty-based HTTP client opens TCP connections into its pool and defers the TLS handshake until a request needs to be sent. We have observed gaps of more than 20 seconds between TCP connect and ClientHello.

Any SNI-routing TCP proxy has a bounded window in which it waits for a ClientHello in order to read the SNI and select a backend and certificate. OpenShift's HAProxy router uses tcp-request inspect-delay 5s. When the Designer's handshake begins after that window has expired, the proxy has already classified the connection as "no SNI" and serves its fallback certificate. The Designer then rejects that certificate and the operation fails.

The SNI is present and correct in the ClientHello. The problem is purely one of timing: the routing decision is made before the client sends it.


Impact

  • File -> Save fails intermittently with Error reading updated project from Gateway.

  • The failure rate depends on which pooled socket the save RPC happens to select, so it appears random. In our environment it occurred several times per hour of active editing.

  • Two distinct error messages result from the same underlying cause, which makes the issue hard to diagnose:

    • javax.net.ssl.SSLHandshakeException: PKIX path building failed ... unable to find valid certification path to requested target
    • java.security.cert.CertificateException: No subject alternative DNS name matching <host> found

    Which one appears depends only on whether the fallback certificate happens to chain to a CA present in the relevant trust store.


Root cause

  1. Jetty's HttpClient (used by GatewayInterface for RPC) pre-opens TCP connections into its pool without performing the TLS handshake.
  2. The handshake is triggered lazily, when a request is dequeued onto that connection.
  3. The proxy's SNI inspection window (5 s in OpenShift, comparable limits exist in other proxies) expires first.
  4. The connection is routed to the no-SNI backend, which serves the router's default certificate rather than the route's certificate.
  5. The Designer Launcher pins the certificate the user trusted at setup, so any other leaf fails validation regardless of whether it chains to a trusted CA.

Evidence

HAProxy access log (router side)

The two lines that establish the timing. Client IP and hostname anonymised.

2026-08-28T13:06:46.735955Z haproxy[4258]: <client>:63200 [28/Aug/2026:13:06:25.389]
    public_ssl be_no_sni/fe_no_sni 5003/0/21346 4357 -- 63/32/0/0/0 0/0

2026-08-28T13:06:46.735878Z haproxy[4258]: <client>:63200 [28/Aug/2026:13:06:30.391]
    fe_no_sni/1: SSL handshake failure (error:0A000416:SSL routines::ssl/tls alert certificate unknown)

Reading these:

  • TCP connect at 13:06:25.389.
  • 5003 ms is the inspect-delay expiring with no ClientHello received. At 13:06:30.391 the connection is handed to be_no_sni / fe_no_sni.
  • Total connection lifetime 21346 ms: the client began its handshake at approximately 13:06:46.7, 21 s after connecting and 16 s after the routing decision had already been made.
  • alert certificate unknown is the client rejecting the fallback certificate.

Client-side -Djavax.net.debug=ssl:handshake (same connection)

SNI was present and correct:

"ClientHello": {
  "extensions": [
    "server_name (0)": { type=host_name (0), value=ignition.example.com },
    ...
  ]
}

Server response on that handshake:

"Certificate": { "certificate_list": [ {
    "issuer"  : "CN=ExampleIssuingCA, DC=...",
    "subject" : "CN=*.router-default.example.com",
    SubjectAlternativeName [ DNSName: *.router-default.example.com ]

That is the router's fallback certificate, not the certificate configured on the Route.

Immediately followed by:

javax.net.ssl|ERROR|C2|WebSocket@...-44|Fatal (CERTIFICATE_UNKNOWN): PKIX path building failed ...
15:06:46.736 [Designer-misc-1] ERROR designer.update-and-save - Push/pull returned exception.
  at jdk.proxy2/jdk.proxy2.$Proxy11.push(Unknown Source)
  at com.inductiveautomation.ignition.designer.IgnitionDesigner.handleSave(IgnitionDesigner.java:1451)

Successful saves in the same session show handshakes beginning within milliseconds of connect, reaching fe_sni and receiving the correct route certificate. The only difference between success and failure is the connect-to-handshake delay.


Reproduction

Environment: a gateway behind any TCP proxy that selects the backend and certificate by SNI and has an inspection timeout, where the proxy's fallback certificate differs from the route certificate. OpenShift 4.x edge-terminated Route is the reference case, nginx ssl_preread or an F5 with SNI-based pool selection should behave the same.

  1. Configure a Route with termination: edge and a certificate for ignition.<domain>, on an IngressController whose defaultCertificate is for a different domain.
  2. Enable router access logging (spec.logging.access on the IngressController) so the fe_no_sni fallback is visible.
  3. Add -Djavax.net.debug=ssl:handshake to the Designer Launcher's JVM arguments.
  4. Launch the Designer against that gateway and open a project with several Perspective views. More open views means more pooled connections and a higher hit rate.
  5. Edit a resource, wait 30 to 60 seconds without other activity so pooled sockets age past the inspect window, then File -> Save.
  6. Repeat. Failures appear within a handful of attempts.

Correlate by client source port: find the be_no_sni/fe_no_sni line in the router log and match its port against the failing handshake in the Designer log. The Tq timer in the HAProxy log shows the inspect-delay value (5003), and the total time field shows how long the connection sat idle before handshaking.

Great report! Please open a support ticket in the help center and link back to this forum post.