A TLS handshake failure usually means the service was never provisioned

2026-08-25 · Nikhil “Nick” Harinath · ~4 min

You follow a provider's quickstart, build the endpoint URL exactly as documented, and get:

curl: (35) error:0A000126:SSL routines::unexpected eof while reading

or some variant of "TLS handshake failure". So you start debugging TLS. Certificate chain. CA bundle. Cipher suites. openssl s_client. Corporate proxy. System clock skew.

Almost none of that is ever the cause. Here's the rule I now apply first:

A TLS handshake failure against a managed provider endpoint that follows a documented naming pattern almost always means the service is not enabled for your account — not that anything is wrong with TLS.

Why it presents this way

Provider endpoints are usually account-scoped subdomains — something shaped like <your-account-id>.service.provider.com or <your-name>.workers.example.

The pattern is documented, so you can construct the hostname before it exists. And provider DNS often resolves the whole wildcard, so the name resolves and the TCP connection opens. But nothing is listening that can complete a TLS session for a tenant that was never created.

Resolvable name, open port, no valid TLS peer. From the client side, that is indistinguishable from a certificate problem — which is why the error sends everyone down the wrong path.

The two-minute triage

  1. Does a different, definitely-live endpoint on the same provider work? If yes, your TLS stack, CA bundle and clock are all fine. Stop looking at them.
  2. Check the API, not the URL. Provider APIs usually return a much clearer error than the raw endpoint does. In one case I hit, the API returned 10042 — please enable this product through the dashboard, which is the actual answer stated plainly. The endpoint just failed at TLS.
  3. Confirm the service is switched on for the account. Enabling a product is frequently a separate opt-in from having billing configured — an existing payment method on file does not imply the product is active.

Then wait, and don't re-debug

The part that catches people twice: provisioning is not instant, and the error doesn't change while it happens.

After enabling the product, the same handshake failure — and the same API error code — can persist for several minutes. Nothing you do makes it resolve faster, and there is no signal that it's progressing. It simply starts working, with no further action.

If you don't know that, those minutes are exactly when you undo your correct fix and go back to debugging TLS.

The sibling bug: dig works but curl doesn't

Closely related, same "the service didn't exist yet" root cause, different symptom:

$ dig +short new-endpoint.provider.com
104.x.x.x                     # resolves fine

$ curl https://new-endpoint.provider.com
curl: (6) Could not resolve host

Your resolver cached the NXDOMAIN from when you queried the name before it was provisioned. Negative caching is doing its job; the record is now real but your machine still remembers that it wasn't.

On macOS:

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

Instant fix. dig bypasses the system resolver, which is exactly why the two tools disagree — and why that disagreement is the tell rather than a mystery.

The general shape

When a networking error arrives from a layer you didn't configure, ask whether the thing you're connecting to exists yet before you interrogate the protocol. Provisioning failures wear the costume of transport failures, and the costume is convincing.

Related notes

← All notes  ·  Work with me