Claude Code SSL Certificate Error: 5 Fixes That Work (2026)
Claude Code throwing SELF_SIGNED_CERT_IN_CHAIN behind a corporate proxy? 5 fixes: OS trust store, NODE_EXTRA_CA_CERTS, and HTTPS_PROXY, without disabling TLS.
Claude Code that worked at home stops at the office with a wall of TLS noise: SELF_SIGNED_CERT_IN_CHAIN, unable to get local issuer certificate, or a blunt Self-signed certificate detected. Nothing is wrong with your install. Your company’s network is opening every HTTPS connection, re-signing it, and Claude Code does not recognize the new signature.
The fix is almost never to disable certificate checks. It is to teach Claude Code to trust the one certificate your company added. This guide covers the five ways to do that, in the order you should try them, plus the proxy settings that go with them and the one “fix” that quietly hands your API key to anyone on the wire.
The 30-Second Diagnosis
Read the error string first. It tells you which layer is failing, and each maps to a specific fix below.
| Error string | What it means | First fix to try |
|---|---|---|
SELF_SIGNED_CERT_IN_CHAIN | A proxy re-signed traffic with a CA you don’t trust | Fix 1 (OS store) or Fix 2 (NODE_EXTRA_CA_CERTS) |
unable to get local issuer certificate | The issuing CA isn’t in any store Claude Code reads | Fix 2 (NODE_EXTRA_CA_CERTS) |
Self-signed certificate detected | Claude Code’s own wording for the two above | Fix 1, then Fix 2 |
CERT_HAS_EXPIRED | Clock skew, or a stale intercept cert | Check system clock, then Fix 1 |
curl: (35) TLS connect error on install | Handshake fails before install even starts | Fix 3 (install-time flags) |
schannel: ... SSL/TLS secure channel (Windows) | Windows trust or TLS version at install | Fix 3 (TLS 1.2, revocation) |
One test settles the cause in ten seconds. Run Claude Code on a network without inspection, a phone hotspot works, or ask IT for a bypass rule on api.anthropic.com. If it connects there and fails on the corporate network, the proxy is re-signing your traffic and you need a CA fix, not a reinstall.
Fix or Route Around It: When Each Makes Sense
Before you touch a config file, decide which problem you actually have. The certificate fixes below assume you can get your company’s CA and set an environment variable. That is not always true, and forcing it wastes an afternoon.
When to add the CA (most cases)
- You control the machine and can set environment variables or edit
~/.claude/settings.json. - IT can hand you the root CA file, or it is already installed in your OS trust store.
- The proxy uses plain pass-through or basic authentication.
When to route through a gateway instead
- The proxy demands NTLM or Kerberos authentication. Claude Code does not speak either, and no CA import changes that.
- You cannot obtain the corporate CA and IT will not allowlist Anthropic’s domains.
- You need one egress point with its own TLS termination for a whole team, so per-developer CA juggling stops being worth it.
The stop rule
If Claude Code connects on a direct network and only breaks behind the corporate proxy, this is a trust problem, full stop. Do not reinstall, do not switch Node versions blindly, do not open a support ticket about a “broken binary.” Skip to Fix 1. If it also fails on a clean network, the cause is something else (DNS, a regional block, an expired subscription) and the certificate fixes here will not help.
Why Claude Code Rejects the Certificate
Most corporate networks run a TLS-inspection proxy: Zscaler, Netskope, Cato, CrowdStrike Falcon, or a full-tunnel VPN doing the same job. That box exists to read outbound HTTPS for data-loss prevention and malware scanning. To read an encrypted stream it has to sit in the middle: it terminates your connection to api.anthropic.com, decrypts it, then makes its own connection onward and re-signs the response with the company’s private certificate authority.
Your browser trusts that re-signed certificate because IT pushed the corporate root CA into the browser and OS trust stores when they set up the laptop. Claude Code is a separate runtime with its own idea of what to trust, and that is where the mismatch lives.
flowchart LR
A[Claude Code] -->|HTTPS| B[TLS-inspection proxy]
B -->|decrypts, re-signs<br/>with corporate CA| C[api.anthropic.com]
C -->|real Anthropic cert| B
B -->|re-signed cert| A
A -->|corporate CA<br/>not in trust store| D[SELF_SIGNED_CERT_IN_CHAIN]
Here is the part most write-ups get wrong. Modern Claude Code already reads your OS trust store. By default it trusts both its bundled Mozilla CA set and the operating system’s certificate store. Reading the OS store needs a runtime that exposes tls.getCACertificates: the native installer always has it, and npm installs need Node 22.15 or later. On older Node, only the bundled set and NODE_EXTRA_CA_CERTS apply. So when IT has installed the corporate root in the OS store and you are on a current build, inspection proxies like Zscaler and CrowdStrike Falcon work with no extra configuration at all. The errors show up in the gaps: an old npm-based install, a CA that never made it into the OS store, or a runtime launched in a way that skips it.
Reading the SSL Error: Strings and Scope
The exact string narrows the cause. This is the same taxonomy Node and OpenSSL use, so it applies whether Claude Code runs on the native binary or an npm install.
| Error | Layer | Root cause | Scope |
|---|---|---|---|
SELF_SIGNED_CERT_IN_CHAIN | TLS verify | Proxy’s root CA absent from the trust store | Every API call |
unable to get local issuer certificate | TLS verify | Intermediate or root CA missing from the chain | Every API call |
CERT_HAS_EXPIRED | TLS verify | Wrong system clock, or a stale intercept cert | Every API call |
schannel: ... secure channel | Windows TLS | Windows trust store or TLS version mismatch at install | Install step |
CRYPT_E_NO_REVOCATION_CHECK (0x80092012) | Windows revocation | Network blocks the revocation (OCSP/CRL) lookup | Install step |
CRYPT_E_REVOCATION_OFFLINE (0x80092013) | Windows revocation | Revocation endpoint unreachable behind the firewall | Install step |
The split matters. A verify error on every API call is a trust-store problem you fix once with a CA. A revocation error at install time is the firewall blocking a lookup, and you work around it for the single install command rather than changing your trust configuration.
The Fixes, In Order
Work top down. The earlier fixes are cleaner and less risky than the later ones.
Fix 1: Let Claude Code use the OS trust store
If IT already put the corporate CA in your system store (they almost always do, because the browser needs it), the cleanest fix is to make sure Claude Code reads that store rather than fighting it.
On the native installer this is automatic. On an npm install, confirm your Node is 22.15 or newer:
node --version
If it is older, upgrade Node or switch to the native installer, which never depends on the Node version for trust. The default for CLAUDE_CODE_CERT_STORE is already bundled,system, so Claude Code reads the OS store out of the box. You only touch this variable if someone forced it to bundled, which drops the OS store; in that case put system back:
export CLAUDE_CODE_CERT_STORE=bundled,system
Expected result: Claude Code trusts what your OS trusts, including the corporate root. Forcing system alone adds no trust the default did not already have, so it will not rescue a runtime too old to read the OS store. If the OS store itself is missing the CA, that is Fix 2.
Fix 2: Point NODE_EXTRA_CA_CERTS at the corporate CA
This is the workhorse fix, and the one Anthropic’s docs name for TLS-inspection environments. It adds your corporate root on top of the built-in set without replacing anything.
First get the CA file in PEM format. Ask IT, or export it yourself: on macOS open Keychain Access and export the corporate root as a .pem; on Windows run certmgr.msc, open Trusted Root Certification Authorities, and export as Base-64 encoded X.509; on Linux the file usually already lives under /usr/local/share/ca-certificates or /etc/pki/ca-trust.
Then point Claude Code at it:
export NODE_EXTRA_CA_CERTS=/path/to/corporate-ca.pem
claude
Expected result: API calls succeed because Claude Code now trusts the proxy’s re-signed certificate. Make it permanent by adding the export to ~/.zshrc or ~/.bashrc. If your CA bundle has multiple certs (a root plus intermediates), concatenate them into one PEM file; NODE_EXTRA_CA_CERTS reads them all.
Fix 3: Fix the install step separately
The install and the runtime are two different network calls, and they can fail independently. If curl chokes before Claude Code is even installed, patch the install command, not your shell profile.
Point the installer’s curl at the same CA bundle:
curl --cacert /path/to/corporate-ca.pem -fsSL https://claude.ai/install.sh | bash
On Windows, if you see the schannel secure-channel error, force TLS 1.2 first:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
irm https://claude.ai/install.ps1 | iex
If Windows reports CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_REVOCATION_OFFLINE, the network is blocking the certificate revocation lookup, which is common behind corporate firewalls. Add best-effort revocation to the install only:
curl --ssl-revoke-best-effort -fsSL https://claude.ai/install.cmd -o install.cmd && install.cmd && del install.cmd
Expected result: the binary installs. Runtime API calls are still governed by Fix 1 or Fix 2, so set those too.
Fix 4: Configure the proxy itself
Sometimes the certificate is fine but the proxy is not being used. Claude Code reads the standard proxy variables. HTTPS_PROXY is the one that matters for API traffic:
export HTTPS_PROXY=https://proxy.example.com:8080
export HTTP_PROXY=http://proxy.example.com:8080
export NO_PROXY="localhost,127.0.0.1,.internal.example.com"
NO_PROXY takes a space- or comma-separated list, and * bypasses the proxy for everything. If the proxy needs basic auth, put the credentials in the URL:
export HTTPS_PROXY=http://username:password@proxy.example.com:8080
Two limits worth knowing before you burn time on them. Claude Code does not support SOCKS proxies. And it does not handle NTLM or Kerberos proxy authentication, which is exactly the case the next section is about.
Fix 5: mTLS and client-certificate environments
Some enterprises require a client certificate, not just a trusted server one. Claude Code supports mutual TLS through three variables:
export CLAUDE_CODE_CLIENT_CERT=/path/to/client-cert.pem
export CLAUDE_CODE_CLIENT_KEY=/path/to/client-key.pem
export CLAUDE_CODE_CLIENT_KEY_PASSPHRASE="your-passphrase"
Expected result: Claude Code presents the client certificate during the handshake, satisfying a proxy or gateway that authenticates callers by certificate rather than by header.
The anti-fix: never disable verification
You will find NODE_TLS_REJECT_UNAUTHORIZED=0 recommended on forums. It makes the error disappear because it tells Node to accept any certificate from anyone. That includes an attacker sitting on the same coffee-shop network, who can now read the API key you send on every request in plaintext. It is the one line you should never commit. Adding the CA keeps validation on and trusts only the certificate you chose; disabling validation trusts everything. Those are not close.
A Full Walkthrough: Zscaler on macOS
Abstract steps are easy to fumble, so here is the whole thing end to end for the most common setup, a Mac behind Zscaler. It takes about five minutes.
First, confirm it is really the proxy. Tether to your phone and run claude. If it connects there, the corporate network is intercepting and you continue below.
Export the Zscaler root from the Keychain. Open Keychain Access, search for the corporate root (often named Zscaler Root CA), select it, and use File then Export Items to save it as zscaler-root.pem in your home folder. If it exports as .cer, convert it:
openssl x509 -inform der -in zscaler-root.cer -out zscaler-root.pem
Point Claude Code at it and make it stick:
echo 'export NODE_EXTRA_CA_CERTS="$HOME/zscaler-root.pem"' >> ~/.zshrc
source ~/.zshrc
Open a fresh terminal so the export is loaded, then start claude. The SSL error is gone.
Verify the fix actually took
Do not trust “it seems to work.” Confirm Claude Code and your shell agree on the certificate. This one-liner runs a request through the same CA and should print the certificate chain and SSL certificate verify ok:
curl --cacert "$NODE_EXTRA_CA_CERTS" -svo /dev/null https://api.anthropic.com 2>&1 | grep -E "issuer|verify"
If curl verifies with that bundle but claude still fails, the variable is not reaching Claude Code’s process. That is the shell-versus-settings.json gap covered next, not a certificate problem.
Docker, CI Runners, and Remote Dev
Containers are where this error resurfaces after you thought it was solved, because a fresh container does not inherit your laptop’s OS trust store. Your host trusts the corporate CA; the Ubuntu base image inside Docker does not.
Bake the CA into the image and register it in both the OS store and the Node variable:
COPY corporate-ca.pem /usr/local/share/ca-certificates/corporate-ca.crt
RUN update-ca-certificates
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corporate-ca.crt
The same logic covers CI runners and remote dev boxes: a GitHub Actions or GitLab runner behind the same proxy needs the CA present in the job environment, usually as a secret file written at the start of the job with NODE_EXTRA_CA_CERTS exported before any claude step. Devcontainers need the ENV line above in their Dockerfile. If you only fixed your shell profile, the container never saw it.
settings.json vs the Shell
Every variable above can live in the env block of ~/.claude/settings.json, which is the tidy option for a machine you configure once:
{
"env": {
"NODE_EXTRA_CA_CERTS": "/path/to/corporate-ca.pem",
"HTTPS_PROXY": "https://proxy.example.com:8080"
}
}
There is a caveat worth stating plainly. Some earlier versions ignored NODE_EXTRA_CA_CERTS when it was set only in settings.json, and the desktop app did not always forward it to the CLI subprocess it spawns. Both have surfaced as tracked GitHub issues. If the settings.json value does nothing, the reliable fallback is the shell export in your profile, which every build honors because Node reads it before Claude Code starts.
| Where you set it | Reliability | Use when |
|---|---|---|
Shell profile (.zshrc/.bashrc) | Highest, every build reads it | Anything, especially if settings.json seems ignored |
~/.claude/settings.json env block | High on current builds | You want one committed config per machine |
| Desktop app environment | Lowest, may not reach the CLI subprocess | Only after confirming the CLI actually inherits it |
Common Related Errors (and Fixes)
These show up next to the certificate errors and get mistaken for them.
| Symptom | Cause | Fix |
|---|---|---|
curl: (56) Failure writing output on install | Download interrupted, often by the proxy | Retry, or use brew/winget which avoid piped curl |
Install returns HTML or 403 | Region unsupported, or a proxy blocking downloads.claude.ai | Confirm your region is supported (App unavailable in region), then allowlist the domain or set HTTPS_PROXY |
unable to get local issuer certificate at install | CA missing during the curl step | Add --cacert (Fix 3) |
| MCP server over HTTPS won’t trust its cert | The MCP endpoint uses a self-signed cert | Add that cert to NODE_EXTRA_CA_CERTS too |
| Works in terminal, fails in the IDE extension | The IDE process didn’t inherit your shell env | Set the vars in the IDE settings, or launch it from a terminal |
That last row is the quiet one. If claude works in your terminal but the VS Code or JetBrains panel throws the SSL error, the editor was launched from the dock and never saw your .zshrc. Set the variables in the IDE’s own environment, or start the editor from a shell where they are already exported.
When the Proxy Won’t Budge: Route Through a Gateway
If the proxy demands NTLM or Kerberos, or you simply cannot get the CA, adding certificates is a dead end. Anthropic’s own network guidance says as much: for proxies requiring advanced authentication, put an LLM gateway in front that speaks that scheme. A gateway terminates its own TLS and handles the messy proxy negotiation once, so every developer points at one endpoint instead of each person fighting their own trust store.
That is what ofox is: an OpenAI- and Anthropic-compatible gateway at https://api.ofox.ai. Pointing Claude Code at a custom endpoint is a one-line change, the same swap covered in our Claude Code endpoint switch tutorial. Set two variables:
export ANTHROPIC_BASE_URL=https://api.ofox.ai/anthropic
export ANTHROPIC_API_KEY=sk-ofox-...
Be honest about what this does and does not solve. The corporate proxy still re-signs traffic to api.ofox.ai, so you may still need the corporate CA in your trust store for the gateway host. What the gateway buys you is one egress endpoint for the whole team, a single billing view across Claude, GPT, and Gemini, and built-in fallback when one upstream is unreachable. For the full base-URL swap and model routing, see our guide on custom API setup for Cursor, Claude Code, and Cline, and for cost control once it connects, the Claude Code hybrid routing pattern. If you are also weighing a move off Claude Code entirely, the same trust rules apply in our Claude Code to Codex migration guide.
The gateway is the escape hatch, not the default. When you can get the CA, Fix 1 or Fix 2 is simpler and keeps you on the direct path.
FAQ
How do I fix SELF_SIGNED_CERT_IN_CHAIN in Claude Code? A TLS-inspection proxy re-signed the connection with a CA you don’t trust. Install that CA in the OS trust store (the native installer and Node 22.15+ read it automatically) or point NODE_EXTRA_CA_CERTS at the CA bundle. Do not disable validation.
What is NODE_EXTRA_CA_CERTS and where do I point it? A Node variable that adds trusted certificates on top of the built-in set. Point it at your corporate root in PEM format: export NODE_EXTRA_CA_CERTS=/path/to/corporate-ca.pem. Set it in the shell or in settings.json.
Does Claude Code read the Windows or macOS certificate store? Yes, by default it trusts the bundled Mozilla set plus the OS store. Reading the OS store needs the native installer or Node 22.15+; older Node uses only the bundled set and NODE_EXTRA_CA_CERTS.
Is NODE_TLS_REJECT_UNAUTHORIZED=0 safe? No. It turns off certificate validation for every request, exposing your API key to anyone on the path. Add the CA instead.
Why does Claude Code fail with an SSL error when curl works? They read different trust stores. System curl usually already trusts the corporate CA; Claude Code’s runtime may not, or an npm install is on Node older than 22.15. Point NODE_EXTRA_CA_CERTS at the same CA, or move to the native installer or Node 22.15+ so it reads the OS store. (CLAUDE_CODE_CERT_STORE defaults to bundled,system, so forcing system adds nothing.)
Can I set NODE_EXTRA_CA_CERTS in settings.json? Yes, in the env block. Some older versions honored only the shell export, so if settings.json does nothing, export it in your shell profile.
Does Claude Code support SOCKS or NTLM proxies? No SOCKS, and no NTLM or Kerberos auth directly. It reads HTTP_PROXY, HTTPS_PROXY, and NO_PROXY, with basic auth as user:password in the URL. For NTLM or Kerberos, front it with a gateway.
How do I get my company’s CA certificate file? Ask IT for the root CA in PEM format, or export it from Keychain Access (macOS), certmgr.msc (Windows, Base-64 X.509), or /usr/local/share/ca-certificates (Linux).
Sources Checked for This Refresh
- Claude Code: Troubleshoot installation and login, verified 2026-07-03. Source for the TLS/SSL error strings,
--cacertinstall fix, Windows TLS 1.2 and--ssl-revoke-best-effort, andHTTPS_PROXYinstall-time setup. - Claude Code: Enterprise network configuration, verified 2026-07-03. Source for
NODE_EXTRA_CA_CERTS,CLAUDE_CODE_CERT_STORE, the bundled-plus-OS trust model and the Node 22.15 threshold,HTTP_PROXY/HTTPS_PROXY/NO_PROXY, basic-auth proxy URLs, the no-SOCKS limit, and the mTLS variables. - anthropics/claude-code issue #22512, verified 2026-07-03. Confirms the case where
NODE_EXTRA_CA_CERTSset insettings.jsonwas not respected, motivating the shell-export fallback. - Node.js TLS documentation for
NODE_EXTRA_CA_CERTSbehavior and PEM bundle handling, verified 2026-07-03.


