How to Read Clash Logs: Common Errors Explained, from dial tcp to i/o timeout
Learn how to change log levels and interpret common Clash errors like dial tcp, i/o timeout, and connection refused. Trace log entries to nodes, rules, or DNS.
1. Reproduce the issue, then check logs from that moment
If a website won’t load, don’t start by changing DNS, nodes, TUN, and rules all at once. Open the client’s Logs page, note the current time, and reload the affected page once. Check the entries from a few seconds around that moment instead of picking the scariest-looking error from a screen full of red text.
Log colors indicate severity, not the scope of a problem. A failed background latency test may generate a warning while your browser connection still works. Conversely, a bad direct-connection rule may show only a routine connection entry, with no prominent error.
- Note the client name and version, the core name, and whether the current mode is Rule, Global, or Direct.
- Record the failed domain, the time, and what happened—for example, the homepage loads but images do not.
- Clear the log view or filter by time, then repeat the same action once. Clearing the view does not necessarily delete log files from disk.
- Keep the entries around the failed request, especially the destination, matched rule, outbound policy, and error details.
2. Changing the log level: start with info, enable debug only briefly
Clash clients usually show runtime logs in the Logs section of the sidebar. If the page offers a level filter, check whether it only filters displayed entries or also changes the core’s log level. Setting the filter to Debug alone may not make the core emit debug output.
The configuration field for controlling log verbosity is log-level. Both the original Clash and mihomo use this field. If the client has a Log Level setting, change it there first. If not, use the configuration override or merge feature supported by the client. Don’t assume that editing a subscription-generated file will persist—the next subscription update may overwrite it.
# Place this at the top level of the config; do not indent it under dns or rules
log-level: info
| Level | Use case | Notes |
|---|---|---|
silent | Suppresses routine log output | Switch to a different level when troubleshooting |
error | Shows errors only | May omit rule matches and connection context |
warning | Shows warnings and more severe issues | Useful for quickly spotting repeated connection failures |
info | A good starting point for everyday troubleshooting | Read alongside the destination and outbound policy |
debug | Adds details about DNS lookups, connections, and more | Reproduce briefly, then switch back to avoid excessive logs |
When you need debug output, temporarily set this field to debug, reload the config or restart the core as required by your client, reproduce the issue once, then restore it to info. The configuration field uses warning, but log entries may label the level as WARN or warning. Don’t confuse the two.
Before sharing logs, check for subscription links, access tokens, node passwords, server addresses, and local file paths. Keep the original error and port structure, but don’t post your entire subscription config when asking for help publicly.
3. Check four things in a connection log: destination, rule, outbound, and error
[info] [TCP] 127.0.0.1:53142 --> www.example.com:443
match DomainSuffix(example.com) using Proxy[Node-A]
This simplified entry means an app on your device sent a TCP request from temporary port 53142 to www.example.com:443. A domain-suffix rule matched, and the Proxy policy group selected Node-A for the outbound connection. The temporary port on the left is not the client’s proxy listening port; you don’t need to change any settings to match it.
- Destination: Check whether it’s the domain of the page that failed, or a background request for an update check, latency test, or ad resource.
- Rule: Check which rule actually matched. In Rule mode, rules are usually evaluated from top to bottom, and the first match determines the policy.
- Outbound:
DIRECTmeans a direct connection;REJECTmeans the connection was blocked. A policy group may also show the node it ultimately selected. - Error: Check entries for the same destination at the same time to find the failure reason. Seeing
using Proxyalone does not mean the proxy connection succeeded.
MATCH usually means the request reached the fallback rule; it doesn’t mean the rule engine failed. If a site that should use a specific policy reaches the fallback instead, check whether an earlier rule covers the domain, whether the rule set loaded, and whether the expected config is active.
4. dial tcp: a TCP connection is being made; check the details that follow
dial tcp describes an attempt to connect; it is not a diagnosis on its own. It’s usually followed by an address and the underlying error. Both examples below contain this phrase, but call for different troubleshooting steps:
dial tcp 203.0.113.10:443: i/o timeout
dial tcp 127.0.0.1:7897: connect: connection refused
Remote address failures: identify what the address belongs to
The remote address in the first example could be a proxy server or the destination website for a direct connection. Check the outbound field and config to tell which. If it matches the current node’s server address, investigate the connection from your device to that node first. If it’s a website being accessed via DIRECT, check your local network, routing, and the site itself.
Local address failures: check the listening port first
The second example points to 127.0.0.1:7897 on your device. If this is the proxy address used by your browser or command line, a refused connection usually means no service is listening there or the service failed to start. 7897 is just an example, not a default for every client.
Check the actual Mixed Port or HTTP/SOCKS port shown in the client. If a mixed port is enabled, its configuration field is mixed-port. On Windows, run this command to check whether the example port is listening:
netstat -ano | findstr :7897
Check the local address and LISTENING status in the output, then verify the process PID. A remote connection entry containing that port number does not prove that anything is listening locally. If the client failed to start, fix the startup error before switching nodes.
5. i/o timeout: a wait timed out—it doesn’t automatically mean the node is down
i/o timeout means a network read or write did not finish before its deadline. It can occur while establishing a TCP connection, querying DNS, completing a proxy handshake, or reading data after a connection is established. Those two words alone can’t tell you whether the cause is the ISP route, a remote service, UDP packet loss, or your local firewall.
- Identify what timed out. A timeout from a node server and one from a DNS server involve different parts of the connection. Keep prefixes such as
read udpanddial tcp. - Try another node on the same network. Change only the node selected in the policy group, leave rules, DNS, and TUN settings as they are, then test the same destination.
- Try another network with the same node. For example, switch from Wi-Fi to a mobile hotspot and see whether the same kind of timeout goes away.
- Check whether it affects every site or just one. If only one domain fails, check the site’s status and which rule it matches.
If multiple destinations fail only with the same node, check that node or the route to it first. A single background latency-test timeout while web requests work is not a reason to reset the entire config. The test URL and protocol may differ from your actual traffic.
6. connection refused: handle a refused connection differently from a timeout
connection refused usually means the connection request received an explicit refusal, rather than getting no response at all. Common causes include no service listening on the destination port or a device policy actively rejecting the connection. It doesn’t mean the password is wrong; password or protocol mismatches usually occur during authentication or the handshake, after the connection is established.
- Refused at a local port: Check whether the system proxy, browser proxy extension, or terminal environment variables still point to an old port, and confirm the core is running.
- Refused at the node’s port: Check the server and port in your subscription, update the subscription, and try again. Don’t change every node’s port to 443.
- Refused at a LAN address: Check whether the service is bound only to the loopback address, and review LAN access permissions and firewall settings.
If the log shows address already in use, that means something different: the client tried to listen on a port that is already occupied. Find the process using it, then decide whether to close the existing instance or change the port. If you change it, update the proxy settings in any apps you configured manually.
7. DNS errors: distinguish node hostnames from website domains
no such host usually means a domain lookup returned no usable result. The name may not exist, may be misspelled, or there may be a problem with the resolution path. server misbehaving usually means the resolver returned an error status. When you see these messages, first identify the exact name being resolved instead of replacing the entire DNS config.
lookup www.example.com: no such host
read udp 192.168.1.20:53000->192.168.1.1:53: i/o timeout
The second example shows a UDP read timeout while querying 192.168.1.1:53, so focus on the DNS query path. With DoH, you may instead see connection or TLS errors to port 443 on the resolver. Don’t limit troubleshooting to traditional UDP port 53.
Node server hostname fails to resolve
If the node’s hostname can’t be resolved, the proxy handshake can’t even begin. mihomo’s proxy-server-nameserver field can specify a resolver for proxy server hostnames, but it requires a compatible version and config syntax. Don’t copy it into an older core that doesn’t support it. First confirm which core is running, then check whether its current resolver is reachable before the proxy connection is established.
Only the destination website fails to resolve
Check whether config such as nameserver-policy affects the domain, and whether the client is actually handling DNS for the app. Browser Secure DNS, built-in app resolvers, the system cache, and TUN DNS hijacking can all send queries along different paths.
With Fake-IP enabled, seeing a mapped address within a configured range such as 198.18.0.0/16 in the logs does not automatically mean DNS has been poisoned. Check the domain mapping and outbound result as well. System nslookup only shows the resolution path used for that particular query; by itself, it can’t prove that the browser or core used the same resolver.
8. Other common messages: TLS, EOF, and startup failures
| Log message | What it means and what to check first |
|---|---|
TLS handshake timeout | The TLS handshake did not finish in time. First identify whether the handshake was with a node, destination website, or DoH service, then check the route and protocol settings. |
x509: certificate has expired or is not yet valid | Check the system date, time, time zone, and the peer certificate’s validity period. Don’t hide the cause by skipping certificate verification. |
EOF / unexpected EOF | The connection closed, or a read ended unexpectedly. Check whether it happens consistently, along with the protocol and context; this alone does not prove that traffic was blocked. |
connection reset by peer | The connection was reset. The cause may be the remote host, an intermediary network device, or a protocol mismatch. Compare with other nodes and networks. |
network is unreachable | Check local routes, network interfaces, and IPv6 connectivity, especially after waking from sleep, switching networks, or starting or stopping TUN. |
Parse config error | Fix the config parsing error first. Check YAML indentation, field types, and whether the current core supports the protocol mentioned in the following message. |
The original Clash, Clash Meta, and later mihomo releases do not support exactly the same configuration features. If a subscription includes a protocol or field unsupported by the current core, the error occurs while loading the config; switching nodes usually won’t help. Confirm that the config loaded and the proxy groups were created before investigating connection timeouts.
A TUN startup failure may also involve permissions, a virtual network adapter, or route creation. System proxy and TUN traffic can behave differently. Don’t assume TUN is working just because your browser can connect through the system proxy, and don’t remove system network components as soon as you see a TUN error.
9. Worked example: trace a timeout to the node connection
Suppose a browser request to www.example.com fails and the log shows this simplified entry at the same time:
[warning] [TCP] dial Proxy (match DomainSuffix/example.com)
127.0.0.1:53142 --> www.example.com:443
error: dial tcp 203.0.113.10:443: i/o timeout
- Confirm it’s the same request. The destination domain and timestamp match the action, so this is not a background latency test.
- Confirm the rule is expected. The log shows Proxy. If you intended to use a proxy, leave the rules unchanged for now.
- Check the address that failed. Suppose the current node’s server address is
203.0.113.10:443. The evidence points to a timeout connecting to the node, not an HTTP error returned by the website. - Switch only the node. Select Node-B, keeping the mode and destination unchanged. If the request succeeds, investigate Node-A or the route to it first.
- Test on another network if needed. If Node-A works on a hotspot but keeps timing out on your usual network, the issue is more likely related to the original network path, though this doesn’t identify which device is blocking it.
If the original entry instead shows using DIRECT, the node-related conclusion above does not apply. First find out why the request went direct, then check its rule and outbound in the client’s Connections page. You can temporarily switch to Global mode for comparison, but restore the original mode afterward and fix the rule. Global mode is not a long-term fix for every problem.
10. No log entry? Check the traffic path first, and keep key evidence when asking for help
If reloading the page produces no corresponding entry, suspect that traffic never reached this core or that the log view filtered it out. Check whether the app uses the system proxy, whether a browser extension overrides proxy settings, whether another VPN is connected, and whether TUN actually started. Enabling the system proxy alone does not guarantee that every app or UDP flow will pass through Clash.
You can also test the local mixed port directly. Replace 7897 in the command below with the port shown in your client. In Windows PowerShell, use curl.exe to avoid differences caused by an older alias with the same name.
curl.exe -I --proxy http://127.0.0.1:7897 https://example.com
Check the logs immediately after running the command. If it reports that the local port refused the connection, check whether it is listening and whether the core is running. If a destination connection entry appears, investigate the rule, outbound, and error in that order. The HTTP status only describes this request; it does not replace checks for other apps.
Include this information when reporting a problem
- Client and core versions, OS version, and whether the system proxy or TUN is enabled.
- When it happened, the destination domain, current mode, and final outbound; note whether all sites or just one are affected.
- The full error entry with sensitive details removed, plus nearby context. Don’t share only the words
i/o timeout. - What happened when you tried another node on the same network and another network with the same node, plus the most recent config change.
Follow the same order every time: confirm traffic reaches the core, check the rule and outbound, then pinpoint DNS, connection, or handshake issues. Change one variable at a time and record the result. Once access works again, switch the log level back from debug. That way, when the same error appears again, you can build on what you already know instead of trying every toggle from scratch.