The error, verbatim
Jump to the fix ↓APIConnectionError: Connection error.
at OpenAI.makeRequest (file:///C:/project/node_modules/openai/client.mjs:911:19)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5) {
status: undefined,
headers: undefined,
requestID: undefined,
cause: [TypeError: fetch failed] {
[cause]: Error: unable to verify the first certificate; if the root CA is installed locally, try running Node.js with --use-system-ca
at TLSSocket.onConnectSecure (node:internal/tls/wrap:1649:34) {
code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
}
}
}
Tested on
- openai (JS)
- 7.30.0
- @anthropic-ai/sdk
- 0.131.0
- Node
- 24.14.0
- OS
- Windows 11 Pro
Contents
“Connection error.” means the SDK never got an answer from the API at all: no status code, no error body. It says nothing about your API key, your model or your code. The SDK’s message is the same for every cause, and both OpenAI’s and Anthropic’s SDKs use the same class and wording. The real reason is two levels down, in the error’s cause.
Read the cause first
Log the cause chain instead of the message:
try {
await client.chat.completions.create({ /* … */ });
} catch (err) {
console.error(err.cause?.cause ?? err.cause);
}Then match it here:
| Cause in the error | What it means | Go to |
|---|---|---|
ECONNREFUSED |
Nothing is listening at that address | 1 |
ENOTFOUND |
The host name doesn’t exist | 2 |
UNABLE_TO_VERIFY_LEAF_SIGNATURE |
Something is replacing the API’s HTTPS certificate | 3 |
| Fails only on a work network that requires a proxy | Node isn’t using your proxy | 4 |
If the message is Request timed out. instead (APIConnectionTimeoutError), the connection was made but the answer took longer than the SDK’s timeout. That’s a different problem: raise timeout, or ask for less.
1. ECONNREFUSED: a local model server that isn’t running
The most common one now. You point baseURL at Ollama, LM Studio or a local proxy, and it isn’t started:
APIConnectionError: Connection error.
cause → TypeError: fetch failed
cause → AggregateError: ECONNREFUSED
That was baseURL: 'http://localhost:11434/v1' (Ollama’s port) with nothing running. Anthropic’s SDK with the same address failed identically.
Start the server, then check the address answers from the same machine before blaming the SDK:
curl http://localhost:11434/v1/modelsIf curl can’t connect either, it’s the server or the port, not your code.
2. ENOTFOUND: a typo or a wrong base URL
APIConnectionError: Connection error.
cause → TypeError: fetch failed
cause → Error: getaddrinfo ENOTFOUND api.openai.con
One letter off in baseURL (or in an environment variable like OPENAI_BASE_URL) and the name simply doesn’t exist. The cause prints the exact host it tried, so compare it character by character.
3. Something is replacing the HTTPS certificate
This is the confusing one, because it only happens on some machines. Company SSL inspection and antivirus “HTTPS scanning” both work the same way: they decrypt your traffic and re-sign it with their own certificate. Node doesn’t trust that certificate by default, so the connection fails:
APIConnectionError: Connection error.
cause → TypeError: fetch failed
cause → Error: unable to verify the first certificate; if the root CA is installed locally,
try running Node.js with --use-system-ca
code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
I hit this for real. The test machine runs Avast, whose Web Shield intercepts HTTPS: the certificate Node received for api.openai.com was issued by Avast Web/Mail Shield Root, not by OpenAI’s CA. With nothing telling Node to trust that root, both SDKs failed against the real APIs with the message above.
Node’s own hint is the fix. Tell Node to trust the certificates Windows already trusts, which includes the antivirus or company root:
node --use-system-ca app.jsOr set it once in the environment, so every Node process picks it up:
NODE_USE_SYSTEM_CA=14. A proxy you set, which Node ignores
On networks where everything must go through a proxy, people set HTTPS_PROXY and expect it to be used. The SDKs call Node’s built-in fetch, and by default it ignores that variable.
I ran a local proxy that logs every connection, set HTTPS_PROXY=http://127.0.0.1:8899, and called the API. The request succeeded, and the proxy log stayed empty: it went straight out, past the proxy. I couldn’t block direct traffic on this machine to show the failure itself, but on a network that only lets traffic out through the proxy, that direct attempt is the one that can’t get through.
On Node 24, tell Node to use the proxy variables:
NODE_USE_ENV_PROXY=1If the proxy itself is down, you’re back to case 1: with the proxy port closed, the error’s cause was connect ECONNREFUSED 127.0.0.1:8898, the proxy’s address rather than the API’s.
What didn’t work
How this was tested
The OpenAI JavaScript SDK 7.30.0 and Anthropic’s 0.131.0 on Node 24.14.0, Windows 11, each making one chat request with a fake key, so the only possible success was a 401 from the real API. Causes were produced on purpose: a baseURL on a closed port, a misspelled host, a request timeout of 1 ms, a local logging proxy, and the machine’s own Avast HTTPS scanning, with Node’s certificate settings added and removed one at a time. I tested the JavaScript SDKs only. Python’s SDKs use the same error class name but a different HTTP client, so their proxy and certificate behaviour may differ.
— N.K., end of entry No.045