First identify whether the log comes from the interface, the core, or the operating system
When a Clash client reports “connection failed,” the interface notification usually shows only the outcome. The runtime log is what helps identify the cause. Clash Meta (now called Mihomo) handles DNS, rule matching, node connections, and TUN forwarding, while the desktop client starts the core, changes system proxy settings, and displays logs. Either layer can report an error, so the first step is not searching for one English line but determining which layer failed.
| Log source | Common entries | Check first |
|---|---|---|
| Client interface logs | Core startup failures, configuration save failures, service mode installation results | Client permissions, core path, configuration file |
| Mihomo runtime logs | DNS queries, rule matches, proxy dialing, connection timeouts | Subscription configuration, nodes, DNS, and network egress |
| Operating system logs | TUN interface creation failures, port conflicts, permission denials | Administrator permissions, firewall, existing processes |
Most desktop clients let you view core output directly from the “Logs” page in the sidebar. In a typical Mihomo desktop client, open “Settings” → “Clash Settings” → “Log Level,” temporarily change the level from info to debug, then return to “Logs” and reproduce the issue. Menu names vary slightly between clients, but the standard configuration field is usually log-level.
log-level: debug
Keep the complete timeline when reproducing the issue
Do not capture only the last red error. A connection typically passes through DNS resolution, rule matching, policy-group selection, node dialing, and the TLS handshake; the final line shows only where the process stopped. Clear the current log first, note the system time, perform one failed action, and keep at least 10 seconds of entries before and after the error.
- Close video streaming, sync, and download programs that are actively using the network to reduce unrelated entries.
- Clear the client log and confirm that the current configuration loaded successfully.
- Visit only one test address, such as
https://example.com. - Record the access time, selected policy group, and node name.
- Export or copy the complete section from the DNS query through the end of the connection.
Which fields should a Clash log line contain?
Display formats vary between Mihomo versions and client wrappers, but the core information is largely the same: time, level, network type, source address, destination address, matched rule, and the final outbound policy. Here is a typical TCP connection entry.
time="2026-07-27T14:32:18.412+08:00" level=info msg="[TCP] 127.0.0.1:53124 --> example.com:443 match DomainSuffix(example.com) using PROXY[HK-01]"
[TCP]indicates that this session uses TCP; DNS, QUIC, and some game traffic may instead use UDP.127.0.0.1:53124is the local source connection entering Clash; the trailing port is usually assigned temporarily by the system.example.com:443is the destination host and port; 443 usually corresponds to HTTPS.match DomainSuffix(example.com)means a domain-suffix rule matched, rather than the final rule being applied directly.using PROXY[HK-01]means the request entered the policy group named PROXY and selected the HK-01 node.
If the log shows using DIRECT, the rule classified the connection as direct. If it shows using REJECT, the configuration actively rejected the request. Switching nodes usually will not change the result; first check rule order, rule-set contents, and the current operating mode. Rules are matched from top to bottom, and a connection that already matches an earlier rule is not checked against later rules.
How to read info, warning, error, and debug
| Level | Purpose | Does it always indicate a failure? |
|---|---|---|
| info | Configuration loading, connection establishment, rule matches | No; mainly useful for tracing the flow |
| warning | Retries, compatibility fallbacks, rule-set update issues | Not necessarily; check whether functionality is affected |
| error | Dial failures, resolution failures, configuration load failures | Usually requires attention |
| debug | More detailed DNS, connection, and protocol status | No; it simply contains more information |
DNS errors: distinguish upstream failures from local listener failures
dns resolve failed, lookup failed, and exchange failed all mean that the domain-resolution path did not return a valid result, but the underlying causes may be completely different. A common flow is: the application sends the query to the system or Mihomo, Mihomo then contacts the configured nameserver, and the result is processed according to fake-ip or redir-host mode. If any link breaks, the interface may show only “DNS failed.”
Check the upstream DNS when you see a timeout
level=error msg="dns resolve failed: lookup example.com: i/o timeout"
level=warning msg="[DNS] exchange failed: context deadline exceeded"
i/o timeout or context deadline exceeded means that no valid response arrived before the deadline. First check whether the DNS addresses in the configuration are reachable from the current network. If you use DoH, also confirm that its hostname can be resolved by default-nameserver; otherwise, you can create a circular dependency in which the DoH hostname must be resolved using the very resolver that is supposed to provide access to DoH.
dns:
enable: true
listen: 127.0.0.1:1053
enhanced-mode: fake-ip
default-nameserver:
- 223.5.5.5
- 1.1.1.1
nameserver:
- https://dns.alidns.com/dns-query
- https://1.1.1.1/dns-query
This example makes the local DNS listener available at 127.0.0.1:1053 and provides a bootstrap resolver for the DoH hostname. Adjust upstream addresses for your network; an upstream reachable on one network may be unreliable or inaccessible on the current Wi-Fi, corporate network, or mobile hotspot.
Confirm that the local DNS port is actually listening
If the log shows bind: address already in use, another process is using the listener port required by the configuration. Port 53 is commonly used by the system DNS service, and ordinary user processes may also lack permission to bind low-numbered ports on some systems. On a desktop, use 1053 instead, then let the client or TUN DNS hijacking handle the queries.
dig @127.0.0.1 -p 1053 example.com
nslookup example.com 127.0.0.1
The dig command explicitly specifies port 1053 and is suitable for macOS or Linux systems with the corresponding tool installed. Windows’ built-in nslookup cannot conveniently specify a non-53 port, so first check the default listener. If the configuration uses 1053, confirm successful binding in the client log or verify it with a port-checking tool.
dial tcp timeout: node, network, or destination site?
dial tcp timeout means that the TCP dialing phase did not complete within the time limit. Focus on where the connection is being dialed: if the destination is the proxy server’s IP and port, the problem is likely between the local machine and the node; if the proxy connection is already established and the client is connecting to the destination site, the issue may involve the node’s egress, the destination site, or rule selection.
level=error msg="dial tcp 203.0.113.20:443: i/o timeout"
level=error msg="connect failed: dial tcp: lookup node.example.net: i/o timeout"
level=error msg="dial tcp 127.0.0.1:7890: connect: connection refused"
- The first line has resolved the node IP, but the TCP connection timed out. Check the node port, current network egress, and firewall.
- The second line could not even resolve the node hostname. Return to the DNS path instead of repeatedly testing the node’s speed.
- The third line shows that the local port 7890 refused the connection. This usually means the core has not started, the configured port is different, or the process has just exited.
Use the local proxy port for repeatable tests
Assuming the configuration sets mixed-port to 7890, first confirm the port, then make a command-line request explicitly through Clash. The request below sets a 5-second connection timeout and a 15-second overall limit, making it easier to distinguish an immediate refusal from a timeout after prolonged waiting.
curl --proxy http://127.0.0.1:7890 \
--connect-timeout 5 \
--max-time 15 \
-I https://example.com
If the command returns Connection refused in under a second, check the core process and local port first. If it reports a connection timeout after about 5 seconds, the local port usually accepted the request, so the problem is more likely in the node dialing stage. If it returns HTTP/2 200 or HTTP/1.1 200 OK, the test address can be reached through the current proxy; the original application may instead be affected by proxy overrides, QUIC, certificates, or its own DNS.
In Windows PowerShell, run the following command first to check whether the local port is reachable:
Test-NetConnection 127.0.0.1 -Port 7890
Seeing TcpTestSucceeded : True only means that the local machine can connect to Clash’s listening port; it does not prove that the remote node works. Continue by checking the policy group, node name, and remote errors in the core log.
The difference between connection refused and network unreachable
| Error | What it means | First action |
|---|---|---|
| connection refused | The destination host explicitly refused the connection, or no local process is listening | Verify the IP, port, core process, and node service status |
| i/o timeout | The read or write operation did not complete before the deadline | Test the network egress, switch nodes, and compare latency |
| network is unreachable | The system has no usable route to the destination network | Check network interfaces, IPv4/IPv6 routes, and TUN status |
| TLS handshake timeout | The TLS handshake after TCP did not complete in time | Check link quality, system time, protocol parameters, and intermediate networks |
| EOF | The peer closed the connection prematurely | Check whether it happens repeatedly and compare other nodes |
How to interpret TUN mode logs
System proxy settings affect only applications that actively read those settings, while TUN mode captures a much broader range of traffic through a virtual network interface. When the browser works but a game or terminal does not, check whether the log contains connection entries for that process: no entry usually means the traffic has not reached Mihomo; a matched rule followed by a dialing failure indicates a problem inside the proxy path.
Common TUN startup errors include operation not permitted, failed to create tun device, and route-write failures. They usually point to permissions, service mode, or virtual interface state. On Windows clients, check whether “Settings” → “Service Mode” is working correctly, then enable TUN again. On macOS and Linux, confirm that the client or core can create virtual interfaces and modify routes.
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
dns-hijack:
- any:53
auto-detect-interface lets Mihomo identify the current default egress. After frequent switches between Wi-Fi, Ethernet, VPN, or a mobile hotspot, if the log still shows the old interface, disable TUN, wait for the system routes to stabilize, and enable it again. Do not let two network tools write default routes and DNS hijacking rules at the same time; the log may otherwise alternate between unreachable-interface and DNS-timeout errors.
What it means when the log contains no destination connection
- The application has its own proxy settings enabled and points to a different port.
- The terminal has no
HTTP_PROXY,HTTPS_PROXY, orALL_PROXYset, and TUN is disabled. - The browser is using QUIC, but the current interception method is not handling the corresponding UDP traffic correctly.
- A LAN device is accessing the local proxy, but
allow-lan, the listener address, or the firewall does not permit the connection. - The TUN virtual interface was created successfully, but the default route was not added or has been overridden by another network tool.
Handle configuration and subscription errors during startup
If the core has not finished loading the configuration, later DNS and node tests are meaningless. YAML is sensitive to indentation, and malformed list items, colons, or string syntax can all prevent startup. Log entries such as parse config error, yaml: line 42, or mapping values are not allowed often point near the error, but the actual problem may be on the preceding line.
proxy-groups:
- name: PROXY
type: select
proxies:
- Auto
- DIRECT
Use consistent spacing at the same indentation level and do not mix tabs with spaces. Quote names containing colons, hash signs, or other YAML special characters. After a subscription update, if you see provider not found, a missing policy-group reference, or a rule-set loading failure, verify that the referenced names exactly match the keys under proxy-providers and rule-providers, including capitalization and spaces.
HTTP status codes can narrow down a subscription update failure
401or403: the link authorization is invalid, access was denied, or the subscription credentials changed.404: the subscription or rule-set path does not exist.429: too many requests were made in a short time. Stop refreshing repeatedly and try again later.500,502, or503: the remote service is temporarily unavailable; try again after a while.- A
200response followed by a parsing failure: the response may not be valid YAML. Check the content type, redirects, and actual response body.
A troubleshooting sequence from symptom to conclusion
The value of logs is not listing every error; it is finding the first point where the normal flow diverged. One failure may produce DNS timeouts, node test failures, and rule-set update failures at once. If the local machine is already offline, all three are different symptoms of the same root cause. A fixed sequence prevents endless switching between unrelated settings.
- Check the basic network: disable the system proxy and TUN, then test whether the current network can access a site that is allowed to connect directly.
- Check configuration loading: look for YAML parsing errors, port conflicts, or provider-reference errors during startup.
- Check the local listener: verify actual ports such as
mixed-port: 7890, then test whether the local machine can connect. - Check DNS: see whether the node hostname and destination hostname resolve, distinguishing a local listener failure from an upstream timeout.
- Check the matched rule: confirm whether the destination uses DIRECT, REJECT, or the expected policy group.
- Check node dialing: compare errors and timing across nodes in two different regions to determine whether only one node is affected.
- Check application interception: when no destination entry appears in the log, review system proxy settings, environment variables, TUN routes, and the application’s own proxy settings.
- Restore normal settings: change the log level back to
infoafter testing and remove temporary proxy environment variables.
For example, a browser reports that it cannot connect, and the log first shows lookup node.example.net: i/o timeout, followed by speed-test failures for multiple nodes. The shared failure point is node hostname resolution, so changing each node’s protocol is not the right approach. In another case, the log clearly shows match MATCH using PROXY[US-02], followed by connection refused only for US-02. If switching to HK-01 succeeds immediately, the issue has been narrowed to one node or its port.
The final report should include at least the client version, Mihomo core version, operating system, network type, current mode, log level, reproduction time, and the complete error excerpt. Version information can show whether configuration fields are supported, while the network type helps assess IPv6, corporate network restrictions, or hotspot switching. Once you answer four questions—did the traffic enter Clash, did DNS complete, which rule matched, and which egress was dialed—most runtime failures can be narrowed from the vague “proxy does not work” to one verifiable step.