1. Classify by the error text first, then decide which layer to inspect
A certificate error is the browser's paraphrase of a failed TLS handshake, not something Clash outputs. Chrome, Edge, and Firefox already name the failing step in the error text. Copy that line down in full, then use the table below to decide which layer to check — far more effective than toggling the proxy on and off.
| Error text | Meaning | Check first |
|---|---|---|
| NET::ERR_CERT_DATE_INVALID | Certificate outside its validity period | System clock, root certificate validity |
| NET::ERR_CERT_AUTHORITY_INVALID | Issuer is not in the local trust store | Missing intermediate certificate, local interception software |
| NET::ERR_CERT_COMMON_NAME_INVALID | Certificate domain does not match the requested domain | DNS resolution result, hosts file entries |
| NET::ERR_CERT_REVOKED | Certificate has been revoked | Problem on the target site's side |
| SSL_ERROR_BAD_CERT_DOMAIN(Firefox) | Domain mismatch — see above | DNS resolution and SNI |
Firefox uses its own NSS certificate store and does not read the system root store. If an enterprise gateway or a packet-capture tool has installed its root certificate on the machine, Chrome may open pages normally while Firefox still reports SEC_ERROR_UNKNOWN_ISSUER. When the same domain behaves differently in two browsers, suspect the certificate store first, not the proxy path.
The command line gives you details faster — two commands are enough:
curl -vI https://example.com --max-time 8
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null
If curl returns SSL certificate problem: unable to get local issuer certificate, the chain is incomplete or the matching root certificate is missing locally; certificate has expired points to a clock or validity issue. Both messages get you closer to the root cause than a browser dialog.
Draw the boundary with one quick test
Quit the client, turn off the system proxy, and open the same domain in the same browser. If the error disappears, the problem lies in the proxy path or the node; if it persists, the problem is in the local certificate store or the site itself and has nothing to do with Clash. Doing this first saves wasted effort later.
2. Step 1: verify the system clock and certificate validity
A certificate's validity is bounded by two timestamps, notBefore and notAfter; if the system clock falls outside that window, the handshake fails. Laptops that sleep for weeks, dual-boot machines, and virtual machines restored from old snapshots all drift by minutes to days — and users rarely notice.
- Windows: Settings → Time & language → Date & time → turn on "Set time automatically", then click "Sync now". From the command line,
w32tm /resyncforces a resync andw32tm /query /statusshows the current time source. - macOS: System Settings → General → Date & Time → turn on "Set date and time automatically". In Terminal,
sudo sntp -sS time.apple.comsets the clock manually. - Linux:
timedatectl statusshows NTP sync state, andsudo systemctl restart systemd-timesyncdrestarts the time sync service.
If the clock is correct but ERR_CERT_DATE_INVALID still appears, look at the root certificate itself. DST Root CA X3 expired on 2021-09-30, and a wave of failures hit older Android devices and legacy OpenSSL clients because servers kept sending cross-signed chains pointing at that root. Where to inspect the local root list: on Windows run certlm.msc → Trusted Root Certification Authorities → Certificates; on macOS open Keychain Access → System → Certificates; on Linux look in /etc/ssl/certs.
The test is simple: if the same domain loads fine on another device with a correct clock, the problem is local time or the local certificate store, not the node — no need to dig further.
3. Step 2: inspect the root certificate chain and local interception software
A missing intermediate certificate is a server-side misconfiguration that often looks like a client-side problem. When a server sends only its leaf certificate and no intermediates, the browser tries to fill the gap from cached intermediates or the AIA extension in the certificate; after a browser switch or cache clear, that fallback fails and you get ERR_CERT_AUTHORITY_INVALID.
openssl s_client -connect example.com:443 -servername example.com -showcerts </dev/null 2>/dev/null | grep -c "BEGIN CERTIFICATE"
A count of 1 means the server returned only the leaf certificate and the chain is incomplete; a healthy response returns 2 to 3. Only the site operator can fix this by sending the intermediate certificates — changing client settings does nothing.
Local interception software is the second most common source. Enterprise gateways, security suites with web filtering, and capture tools (Charles, Fiddler, mitmproxy) install a self-signed root certificate on the machine and re-sign every site certificate you visit. That root lives in the system store, so Chrome and Edge trust it and everything looks fine; Firefox, Java applications, and some Electron clients use their own stores and report errors. Where to check, item by item:
- Windows:
certlm.msc→ Trusted Root Certification Authorities → Certificates, sort by the Issuer column, and look for entries that are not public CAs (corporate domains, security vendor names). - macOS: Keychain Access → System → Certificates, and check for self-signed roots of unknown origin.
- Firefox: Settings → Privacy & Security → Certificates → View Certificates → Authorities, and compare the list entry by entry with the system store.
Do not bypass the error by skipping validation
curl's --insecure flag and the browser's ignore-certificate-errors switch simply turn the check off. The problem goes from a visible error to an invisible risk, and the diagnostic clues disappear with it.
One point needs to be clear here: the Clash and mihomo cores only forward TCP/UDP traffic and apply routing rules. They do not take part in the TLS handshake and do not decrypt HTTPS traffic, so the proxy path itself never swaps certificates. Unless you have added a MITM tool on top, blaming the core for a certificate error is the wrong starting point.
4. Step 3: proxy path, DNS, and routing rules
A domain resolving to the wrong IP is the third source of certificate errors. The CN and SAN fields bind a certificate to a domain name, so when the browser receives a certificate for a different domain it reports ERR_CERT_COMMON_NAME_INVALID. Three common triggers: DNS poisoning returns a wrong address; a hand-written hosts entry is out of date; or a fake-ip address gets pasted into another tool as if it were real.
dns:
enable: true
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- https://223.5.5.5/dns-query
In fake-ip mode, mihomo assigns domains virtual addresses in the 198.18.0.1/16 range. That mapping exists only inside the client and is restored to the domain name when the connection is established, so it never reaches TLS validation. Trouble starts when 198.18.x.x is written into hosts or into a tool that bypasses the proxy — once the domain name is lost, the certificate cannot match.
Routing rules can also cause certificate errors indirectly. A domain matched as direct while the current network hijacks it will return a forged certificate. To check: open the Connections page in Clash Verge, find that connection, and look at the matched rule and the outbound node, then switch the domain to a proxy node and retry. If it works after the switch, the problem is the direct route, not the certificate.
Cases where the system proxy does not cover an app deserve separate treatment. Some applications ignore system proxy settings and connect directly; when blocked, they throw connection resets or timeouts rather than certificate errors, and mixing the two kinds of errors together sends you down the wrong path. Make sure the ports match: mixed-port is often 7890, while Clash Verge builds default to 7897 — browser extensions and the system proxy must point at the same port.
TUN mode takes over traffic at the network adapter layer and does not depend on an app supporting proxies, but it still does not decrypt TLS — certificate validation still happens in the browser. If certificate errors appear in TUN mode, check DNS and routing rules first instead of toggling TUN on and off.
5. A troubleshooting checklist to run in order
- Record the full error text, the domain, and the time it occurred, and note whether the error is constant or intermittent.
- Quit the client, turn off the system proxy, and retry in the same browser to see whether the proxy is involved.
- Sync the system clock, restart the browser, and load the page again.
- Run
openssl s_client -connect example.com:443 -servername example.com -showcertsto confirm the chain is complete and the validity period covers the current time. - Check the system root certificate list and rule out interception certificates installed by an enterprise gateway or security software; Firefox needs a separate check.
- On the client's Connections page, confirm the matched rule, the outbound node, and the DNS resolution result for that domain.
- Switch the domain to another node or policy group and watch whether the error text changes.
- Cross-check on a different network (a phone hotspot, for example) to separate a local network problem from a node-side problem.
Steps 2 and 4 in the checklist give the best return: one draws the line of responsibility, the other reports the actual state of the certificate chain. Most cases are solved by the time you get there.
6. Common misdiagnoses
- Switching nodes fixes certificate errors. Nodes only forward byte streams; the certificate comes from the target site. If the same error appears after switching, the node is effectively ruled out.
- TUN mode changes certificate validation. It does not — TUN changes how traffic is captured, while TLS validation still happens in the browser.
- Updating the subscription fixes certificate errors. Subscription content only affects the node list and rules; it never writes to the system certificate store.
- Clearing the browser cache solves it. It only helps occasionally when an intermediate certificate is missing and the browser had been relying on a cached copy — not a reliable fix.
- Switching to another client fixes it. Mainstream clients share the mihomo core and the same system proxy settings, so changing clients does not change the TLS validation path.
Fix the order: error text → system clock → root certificate chain → proxy and DNS → node. The first two steps cover most cases; treating the core as the prime suspect usually just costs time.