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

**URL:** <https://forum.inductiveautomation.com/t/ign-17717-designer-pooled-connections-defer-tls-handshake-past-the-sni-inspection-window-causing-intermittent-save-failures-behind-sni-routing-proxies/116946>\
**Category:** Ignition\
**Tags:** ignition83, perspective\
**Created:** [August 31, 2026, 6:43am UTC](https://forum.inductiveautomation.com/t/ign-17717-designer-pooled-connections-defer-tls-handshake-past-the-sni-inspection-window-causing-intermittent-save-failures-behind-sni-routing-proxies/116946 "2026-08-31T06:43:07Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![filip.persson](https://avatars.discourse-cdn.com/v4/letter/f/91b2a8/32.png) [@filip.persson](https://forum.inductiveautomation.com/u/filip.persson)\
**Post date:** [August 31, 2026, 6:43am UTC](https://forum.inductiveautomation.com/t/ign-17717-designer-pooled-connections-defer-tls-handshake-past-the-sni-inspection-window-causing-intermittent-save-failures-behind-sni-routing-proxies/116946/1 "2026-08-31T06:43:07Z")

</div>

**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:

* * *

## 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.

```python
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:

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

```

Server response on that handshake:

```python
"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:

```python
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.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [August 31, 2026, 12:41pm UTC](https://forum.inductiveautomation.com/t/ign-17717-designer-pooled-connections-defer-tls-handshake-past-the-sni-inspection-window-causing-intermittent-save-failures-behind-sni-routing-proxies/116946/2 "2026-08-31T12:41:28Z")

</div>

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