Follow the timeline before chasing error keywords
Reproduce one request at a time and find the earliest relevant error. A page failing to load could be caused by traffic interception, DNS resolution, rule selection, a proxy connection, or the destination server. The last timeout in the log is often just a consequence of an earlier failure. Searching for timeout and switching proxies right away can send you down the wrong path.
Clash refers to an ecosystem of cores and clients. The original Clash core, Clash Meta (now called mihomo), and different desktop interfaces don't all use the same log format or expose the same fields. The client's Logs page usually shows core output; errors related to installing the service, permissions, or updates may be recorded separately in the app's own logs. If the core hasn't started, it's normal to see no connection logs.
- Note the local time when the issue occurs, such as
14:32:10, along with the destination domain and the app you were using. - Close unrelated tabs, download managers, and apps that keep making network requests to reduce background traffic.
- Open the Logs page and clear the existing entries in the interface. This usually clears only the display, not log files on disk.
- Refresh the target page once and keep the logs from about 10 seconds before and after.
- Check in this order: did the traffic reach the core → DNS resolution → rule match → outbound connection → application response.
Log levels: use info day to day, debug to reproduce issues
Start with the client's Logs page. For more detail, look in the client settings for “Log level” or Log Level. Some interfaces let you change the core's actual log level; others only filter which lines are displayed without changing how much the core outputs. After switching levels, make the request again and check for new debug details.
| Level | When to use it | What to look for |
|---|---|---|
silent | Not useful for troubleshooting | Output is suppressed, so you can't tell whether connections occurred |
error | Captures only severe errors | Errors such as startup failures, usually without normal connection context |
warning | Monitoring issues | Connection failures, timeouts, and related warnings |
info | Routine checks | Common details such as destination, matched rule, and selected policy |
debug | Brief reproductions | More detailed DNS or internal processing information; varies by version |
Make sure changes apply to the active configuration
Cores that let you set the log level in configuration support the following top-level field. Don't nest it under dns: or tun:. If your client manages subscriptions, use its override or merge mechanism where possible. Direct edits to a downloaded subscription file may be overwritten the next time it updates.
log-level: debug
Save the changes, reload the configuration as required by the client, and verify that the runtime log level actually changed. Switch back to info when troubleshooting is done. Debug output may contain visited domains, private network addresses, and proxy server details. Keeping it enabled long term adds noise and increases the risk of exposing sensitive information when sharing logs.
Connection entries: identify the destination, rule, and outbound
14:32:10 INF [TCP] 127.0.0.1:53124 --> example.com:443
match DomainSuffix(example.com) using DIRECT
This example provides at least four clues: the connection uses TCP; the local source port is 53124; the destination is example.com:443; and a domain-suffix rule matched, selecting a direct connection. The source port is usually assigned temporarily by the app. It isn't Clash's listening port, so don't change mixed-port just because you see it.
- Destination: Check whether the domain or IP matches the action you just took. A webpage may also request images, scripts, and login endpoints, so its homepage domain may not be the only destination.
- Rule: Check the matched rule type and value, not just the name of the final policy group shown.
- Outbound:
DIRECTconnects directly;REJECTblocks the connection according to policy. A proxy group may be followed by the specific proxy it selected. - Result: A connection entry means the core handled the connection. It does not mean the TLS handshake, page load, or application request succeeded.
No relevant logs?
First check that the log view isn't filtered, then check how traffic enters the core. The system proxy affects only apps that honor that setting. If an app has its own proxy settings, verify the listening address and port, such as 127.0.0.1:7890; don't assume every client uses port 7890. For TUN mode, make sure the virtual adapter, route capture, and required permissions are in place.
A browser may reuse an existing connection, so refreshing a page won't always create a new connection entry. Fully quit and reopen the browser, or make a request from a fresh test process, to get a cleaner sample. If a standard proxy test appears in the logs but the original app never does, start by checking how that app's traffic is being captured.
Dial failures: distinguish refused connections, timeouts, and unreachable routes
dial means a connection attempt is being made. The address in the error could be the destination, a proxy server, or an upstream DNS server. Read the full error chain to find out where the connection was headed before deciding whether to check the website, proxy, or local network.
dial tcp 127.0.0.1:7890: connect: connection refused
dial tcp 192.0.2.10:443: i/o timeout
dial tcp [2001:db8::10]:443: connect: network is unreachable
The addresses 192.0.2.10 and 2001:db8::10 above are documentation examples, not testable proxies. The three errors point to different issues: the other end refused the connection, the connection didn't complete in time, or no network route was available.
connection refused: check the address and listening service
If the refused connection is to 127.0.0.1:7890, common causes include the proxy core not running, a changed port, or an app still using an outdated setting. On Windows, check for a TCP listener in PowerShell; on macOS or Linux, check the listening process in a terminal. These commands only inspect the system and won't stop any processes:
# Windows PowerShell
Get-NetTCPConnection -LocalPort 7890 -State Listen
# macOS / Linux; lsof must be installed
lsof -nP -iTCP:7890 -sTCP:LISTEN
If nothing is listening, check the client's running status. If there is a listener, verify that it's the expected core. If a remote proxy address refuses the connection, check the server port in your subscription and whether the service is running. Changing the local mixed port won't fix a refusal from a remote server.
i/o timeout: find out which part timed out
A timeout doesn't mean a proxy is permanently down. It could be caused by packet loss, a firewall silently dropping traffic, an unreachable proxy server, or a slow destination. Keep the destination the same, switch to another proxy in the same policy group, then compare the error address and timing. If every proxy fails, check the local network and proxy server DNS resolution next. Don't change DNS, TUN, and rules all at once.
network is unreachable: check routes and address families
An error address in square brackets usually indicates IPv6. A missing IPv6 route, a conflict with VPN routes, or a TUN capture issue can all make a destination unreachable. First check whether the system itself can reach an address over the same IP family, then inspect route changes. A single IPv6 error doesn't prove the entire request failed; the core may retry over IPv4. Check nearby log entries too.
DNS timeouts: distinguish upstream DNS issues from connection failures
lookup example.com: i/o timeout
exchange failed: context deadline exceeded
lookup example.com: no such host
These examples may indicate a query timeout, a DNS exchange that exceeded its deadline, or a nonexistent name. Actual logs may also include the upstream address, query type, and underlying connection error. no such host is not the same as a timeout: check the spelling first, then look at the source of the response and any filtering settings.
- Identify what's resolving the name: Is it system DNS, the app's own DoH, or mihomo's built-in DNS? A browser's Secure DNS setting can change the path, and TUN DNS hijacking may redirect requests.
- Check that the upstream is reachable: Traditional DNS commonly uses UDP/TCP 53, DoT commonly uses TCP 853, and DoH usually uses HTTPS 443. A reachable port confirms only transport-layer connectivity; it doesn't guarantee that DNS queries will succeed.
- Distinguish the two domains: Both the destination website and the proxy server may need DNS resolution. If the proxy server's hostname can't be resolved, the subsequent proxy connection will fail too.
- Check dependencies: A DNS upstream that requires a proxy may create a startup dependency problem if that proxy itself depends on a hostname that hasn't been resolved yet.
Use system lookups for comparison only
nslookup example.com
This command shows the result through the system's default DNS path, but it doesn't prove that mihomo's built-in DNS is working. When TUN or DNS hijacking is enabled, the core may intercept the query too. To determine whether both use the same path, check the active configuration and upstream details in the logs. Don't conclude that Clash DNS is fine just because the system can resolve a name.
In mihomo, proxy-server-nameserver can be used to resolve proxy server hostnames, while default-nameserver is involved in resolving the hostnames of DNS servers themselves. Check the documentation for your current core version for supported options and exact behavior. Older Clash configurations may not support these fields, so don't copy a whole example meant for a newer core. If you use options such as respect-rules, also check whether DNS requests are routed through a proxy that depends on those same requests.
Rules not matching: check mode, order, and destination type
“Rule not matched” doesn't always appear as a specific error. More often, the log shows Match as the fallback or an unexpected outbound. First confirm that the client is in Rule mode: Global and Direct modes don't select an outbound for each connection using the usual rule-based process.
# Configuration snippet; not a complete subscription
rules:
- DOMAIN-SUFFIX,example.com,DIRECT
- MATCH,DIRECT
Rules are checked in order, and the first match determines the result. The specific domain rule above comes before the fallback. If MATCH is placed first, later rules won't get a chance to handle the connection. This example uses only the built-in DIRECT target. If you substitute a custom policy group, define it under proxy-groups in the complete configuration.
- Domain mismatch:
DOMAINmatches a specific domain;DOMAIN-SUFFIXmatches a suffix and its corresponding subdomains. A login domain after a webpage redirect may fall outside the original rule. - Only an IP is available: Domain rules may not match if an app connects directly to an IP or the domain information isn't preserved. Whether traffic sniffing can recover the domain depends on the protocol, configuration, and core support; not every connection can be recovered.
- Rule set not loaded: Check for provider download or parsing errors during startup or configuration reload. The rule set format must match its
behavior. A successful subscription download doesn't mean every rule set loaded successfully. - Override not merged: Confirm which configuration is currently active. Editing a different file or using the wrong merge level can leave rules out of the runtime configuration.
- Different policy group selection: Even if the expected rule matched, traffic may still use the wrong proxy if the group's manual selection, automatic test result, or nested group target has changed.
For testing, add one temporary rule for the target domain, place it before broader relevant rules, reload, and establish a new connection. Check that both the rule and outbound match your expectations before deciding whether access is fixed. For more on rule syntax and mixed ports, see Deep Dive.
Troubleshoot by timeline: change one variable per test
This troubleshooting timeline is an example, not a real speed test. Suppose you refresh a page at 14:32:10, the expected policy group matches at 14:32:10, and a connection to the proxy server times out at 14:32:15. Check the proxy server path first. If its hostname failed to resolve at 14:32:10, DNS resolution is the earlier failure to investigate.
| What you see | Next step | Avoid for now |
|---|---|---|
| No connection entry for the destination | Check log filters, system proxy, app proxy, or TUN capture | Switching proxies in bulk |
| Proxy server hostname fails to resolve | Check the DNS upstream and startup dependencies | Changing only the destination site's rules |
| Fallback or unexpected rule matched | Check Rule mode, rule order, domain, and active configuration | Assuming a rule is correct based on latency alone |
| Expected outbound connection is refused or times out | Check the remote address and port, then compare with another proxy | Resetting all network settings at once |
| Connection established, but the app still fails | Check TLS, HTTP status, and app logs | Blaming every failure on DNS |
Test the proxy entry point with an explicit request
If the current mixed port is actually 7890, use the request below to test the HTTP proxy entry point. On Windows, curl.exe avoids command alias differences in some PowerShell environments; on macOS and Linux, curl is usually the command to use.
# Windows
curl.exe -I --proxy http://127.0.0.1:7890 --connect-timeout 5 --max-time 15 https://example.com/
# macOS / Linux
curl -I --proxy http://127.0.0.1:7890 --connect-timeout 5 --max-time 15 https://example.com/
Here, 5 seconds is the connection timeout and 15 seconds is the total request timeout. These settings apply only to this curl test; they don't change the core's global timeouts. -I requests response headers. A 403 or 405 from the destination doesn't automatically mean the proxy is broken; check whether the connection was established and where the response came from. This test explicitly uses the local HTTP proxy entry point, so it can't confirm that TUN is capturing traffic from other apps correctly.
If the log shows only that the connection was handled but the browser reports a certificate or login error, check the browser's developer tools for network status and app errors. Clash runtime logs aren't full HTTP captures and usually don't show every response from application endpoints. Core logs help trace the transport path; app logs provide details at higher layers.
Sharing troubleshooting logs: keep context and redact sensitive details
When sending information to maintainers, focus on making the issue reproducible, not on sending as much data as possible. Include about 10 seconds of log text before and after the same request, the current mode, OS version, client version, and core version, and note whether system proxy or TUN is enabled. Record the client and mihomo core versions separately; don't use one as a substitute for the other.
- Describe what you did and what you expected. For example: “Opened the target page; expected the domain rule to match, but it used MATCH instead.”
- Keep the full error chain, rule type, address family, and port. Without them, it's hard to tell whether the issue is local or remote.
- Remove subscription URLs, credentials, controller API secrets, and access tokens.
- You can replace proxy server names, usernames, and private network addresses with consistent labels. Use the same label for the same item throughout.
- Include the most recent change and the results for the same request before and after it. Don't share just one red error line.