Start with a reproducible request
When troubleshooting a Clash connection failure, first identify where it occurs: whether the app sends the request to the client, the core matches a rule, the node address resolves, and the outbound connection is established. FlClash is the client; mihomo is the proxy core it uses. UI errors, subscription download errors, and core forwarding logs may appear in different places.
Open the client’s Logs page and note the current time, operating mode, selected proxy group, and destination that failed. Menu names may vary by client version; look for “Core logs” or “Runtime logs,” not just update history. Then reload one page or send a single test request so background app traffic doesn’t bury the relevant entries.
- Check whether the current mode is
rule,global, ordirect. Custom routing rules can only be troubleshot in rule mode. - Note the current mixed port. The examples below use
127.0.0.1:7890; this is not a universal default across clients. - Keep the logs from about 10 seconds before and after the failure, and note the error shown by the browser.
- Change one setting at a time, then retry the same destination. Don’t switch nodes, DNS, and TUN all at once.
curl -I -v --proxy http://127.0.0.1:7890 --connect-timeout 10 --max-time 20 https://example.com/
This command explicitly uses the local HTTP proxy, with a 10-second connection timeout and a 20-second overall limit. In Windows PowerShell, use curl.exe as the command name to avoid an alias in older environments. Even if the destination returns 403 or 405, first distinguish between “an HTTP response was received” and “the connection was never established.” This tests the proxy entry point; it does not confirm that TUN interception is working.
How to read log levels and fields
mihomo supports silent, error, warning, info, and debug for log-level. Start with info; temporarily switch to debug when you need more detail about DNS resolution and connections. A client may override fields from a subscription, so check the effective configuration rather than only editing the downloaded YAML.
log-level: info
| Level | Primary use | What to look for |
|---|---|---|
error | Errors | Configuration loading or component startup failures; use the message to determine the impact. |
warning | Connection issues | Connection timeouts, resolution errors, and similar events; a single warning doesn’t mean the core has stopped working. |
info | Routine troubleshooting | Startup information, rule matches, and outbound selection. |
debug | Additional detail | DNS resolution and internal processing details; produces a lot of output, so switch back after troubleshooting. |
silent | Disable routine log output | Not suitable for capturing a failure. |
The example below illustrates the format for readability; it may not match every mihomo version exactly. A GUI client may show the time, level, and message in separate columns.
time="2026-09-15T10:24:08+08:00" level=info msg="[TCP] 127.0.0.1:53124 --> example.com:443 match DomainSuffix(example.com) using Manual Selection[Node A]"
time: Use this to correlate entries from the same operation. Check the system time zone first; don’t compare timestamps from different devices as if they used the same zone.[TCP]or[UDP]: Indicates the transport protocol. A website working doesn’t mean UDP-based games or QUIC will work too.127.0.0.1:53124: The connection source and its ephemeral source port.53124is not the proxy listening port.example.com:443: The destination domain and port. Under TUN, you may see the destination IP instead.match: The matched rule type and value;using: The selected policy and node.
An entry showing a matched rule and selected node means routing has been decided; it doesn’t mean the destination site responded successfully. Check nearby connection errors and the actual request result too.
Dial timeouts: identify what the connection is trying to reach
i/o timeout and context deadline exceeded
Both messages mean an operation didn’t finish within its time limit, but these words alone don’t prove that “the node is down.” First check the operation immediately before the error: was it a DNS query, a TCP connection to the proxy server, or a request to the destination through the proxy? An IP in the error chain could belong to the proxy server, DNS server, or destination site; each calls for a different investigation.
dial tcp 203.0.113.10:443: i/o timeout
The addresses above use documentation-only IP ranges to illustrate the format. When troubleshooting, compare the address in the log with the current node’s server and port. If it’s the proxy server, first check connectivity from your local network to that server. If it’s the direct destination, check why the rule selected DIRECT and whether your local network can reach the destination.
- Test two different destinations with the same node. Treat failures across all destinations differently from a failure affecting only one site.
- Keep the rules and DNS settings unchanged and switch only the node. If the connection works afterward, the issue is more likely with the original node or its route.
- Keep the node unchanged and switch between Wi-Fi and mobile data. If only one network fails, check network restrictions, routing, and IPv6 connectivity.
- If only UDP requests fail, check the node protocol and whether the server supports UDP forwarding. Don’t use TCP latency as a substitute for a UDP test.
connection refused and network is unreachable
connection refused usually means the connection was actively rejected, for example because nothing is listening on the port or a firewall rejected it. If the destination is 127.0.0.1:7890, check that the core is running and the port hasn’t changed. If it’s a remote node, verify the node address and port. This is different from a connection that waits until it times out.
network is unreachable usually points to a local routing or address-family issue. For example, the log may show an attempt to connect to an IPv6 address when the current network has no usable IPv6 route. Check routing and the network environment first, then consider changing IPv6-related settings. Don’t disable IPv6 globally based on a single error.
DNS failures: distinguish node domains from destination domains
If you see no such host, DNS resolve failed, or a timeout with DNS query context, first identify the domain being queried. If the proxy server uses a domain name, it must resolve before the proxy connection can be established. A website’s domain may be resolved by local DNS, mihomo DNS, or through the proxy, depending on the entry point and configuration.
| What failed | Key fields | What to check |
|---|---|---|
| Node server domain | proxy-server-nameserver | Check whether the resolver used for the node domain is reachable, and whether resolution depends on the proxy while the proxy itself depends on resolution. |
| DoH server domain | default-nameserver | Check whether bootstrap resolution for the DNS server’s domain is working. |
| Regular destination domain | nameserver、nameserver-policy | Check whether the resolver, domain-based routing policy, and query result are as expected. |
| System and core resolve differently | dns.enable, TUN DNS hijacking settings | Check whether system queries actually reach the core, and whether the app uses its own DoH. |
no such host commonly indicates a lookup failure, such as a nonexistent name, but confirm it against the upstream response. A timeout means no result arrived in time; it doesn’t prove the domain doesn’t exist. The command nslookup example.com usually tests the DNS configured for the system, not mihomo DNS. To test the core’s resolution path, use a tool that targets the actual DNS listening address and port, or check the core’s own logs.
In Fake-IP mode, an app may receive a synthetic address in the 198.18.0.0/16 range. This range is common in related configurations, but the actual fake-ip-range setting is authoritative. Don’t assume this address means DNS has been poisoned. Check the domain mapping, connection interception, and whether fake-ip-filter matches the app’s needs.
Don’t add every domain to
fake-ip-filterjust to remove synthetic addresses from the logs. That changes the resolution path but won’t directly fix an unreachable node, an upstream timeout, or a TUN interception issue.
An unmatched rule isn’t necessarily an error
“Rule not matched” usually describes a routing result; it doesn’t necessarily correspond to an error log. mihomo checks rules in order, stopping when one matches. The final MATCH rule is a catch-all; matching it is normal routing behavior, not a sign that the core failed to parse the rules.
mode: rule
rules:
- DOMAIN-SUFFIX,example.com,DIRECT
- MATCH,PROXY
This is a rule-order snippet, not a complete runnable configuration; PROXY must be the name of an existing policy group or outbound. This snippet sends example.com and its subdomains directly, and routes all other requests through PROXY. If the log shows a request matching an earlier rule, change the order instead of repeatedly switching DNS.
- Check the mode first:
globalanddirectmodes don’t route traffic according to the regular rule list as expected. - Then check the metadata: Domain-based rules may not match as expected when only the destination IP is available. Check whether the app resolved the domain in advance, whether a Fake-IP mapping exists, and whether the appropriate sniffing settings are needed.
- Check the rule source: For
RULE-SET, check whether the correspondingrule-providersloaded successfully, and look for errors in the format, path, or update. - Check the effective configuration: Subscription updates, overrides, and client-side configuration merging can change rule order. Use the runtime configuration as the source of truth.
- Finally, check the policy group: A request can match a proxy policy group and still end up using
DIRECT. A group name containing “Proxy” doesn’t guarantee that traffic ultimately goes through a remote node.
If the request doesn’t appear in the connection log at all, check the traffic entry point first. Some apps ignore the system proxy and need a proxy configured separately or TUN enabled; some requests may also reuse an existing connection. Fully quit the app and send a fresh request—the result is more informative than repeatedly refreshing an old connection.
Port conflicts and TUN startup failures
address already in use: identify the process listening on the port
A typical message is listen tcp 127.0.0.1:7890: bind: address already in use. This means the listening address and port are already in use; it’s not an error from a remote node. Common causes include another proxy client still running in the background or two instances of the same core. Check whether the conflict is on the mixed port, DNS listening port, or controller port.
# Windows: check port 7890; focus on the LISTENING line and its PID
netstat -ano | findstr :7890
# macOS: find the process listening on TCP port 7890
lsof -nP -iTCP:7890 -sTCP:LISTEN
# Linux: find the process listening on TCP port 7890
ss -ltnp 'sport = :7890'
Once you’ve identified the process, quit it through the appropriate app or change its listening port. Don’t terminate an unfamiliar system process. If you change mixed-port from 7890 to 7891, update your browser extensions, command-line environment variables, and any apps with a manually configured proxy address too. On Linux, you may need extra permissions to view processes owned by other users.
TUN permissions and routing issues: check the startup stage first
TUN requires a virtual network device and system permissions. If you see operation not permitted, device creation failures, or route-add errors, check the client’s service mode, system permissions, and virtual adapter status before changing subscription nodes. On Windows, this often involves administrator access or an installed service. The required permissions on macOS and Linux depend on the client’s implementation.
If TUN starts successfully but the destination request never reaches the core, check tun.auto-route, route exclusions, and interference from other VPNs or security software. First quit other apps that modify routing, then test again. Don’t leave the system firewall disabled for troubleshooting; to check for a block, inspect rules for the specific program, interface, and port.
TLS and authentication errors: check the settings after the connection is established
If the log reaches the TLS handshake and then shows x509: certificate has expired or is not yet valid, first check the system date, time, and time zone, then verify the certificate’s validity period. If the certificate name doesn’t match, check the node’s servername or the protocol-specific SNI setting, the server domain, and the server certificate.
EOF, connection reset by peer, and TLS handshake timeout don’t point to a single cause. They can indicate a remote disconnect, mismatched transport settings, network interference, or an incomplete handshake. Consider the protocol, node port, and stage where the error occurred; don’t assume every EOF means the password is wrong.
- Check that the protocol, port, password or UUID, and transport-layer settings match the server.
- For transports such as WebSocket, check the path and Host parameters; use the parameter names specified by the current protocol configuration.
- If the error explicitly indicates authentication failure, first verify the credentials and subscription status.
- Don’t use
skip-cert-verify: trueas a general fix. Skipping certificate verification weakens connection identity checks and won’t fix a port or protocol error.
Follow a consistent troubleshooting order and record retest results
A log may contain traffic from multiple apps, nodes, and retries. Your conclusion should be based on one reproducible request, not the most conspicuous red text on the screen. Following the steps below helps avoid repeatedly changing unrelated settings.
- Startup: Did the configuration load successfully? Did the listening port and TUN start? If startup failed, check syntax, ports, and permissions first.
- Entry point: Does an explicit proxy request reach the core? If the explicit proxy works but the original app fails, check the system proxy, app proxy settings, or TUN.
- Routing: Check the destination, matched rule, policy group, and final node to confirm the request took the expected route.
- Resolution: Identify whether the failed lookup was for a node domain, DNS server domain, or destination domain, then check the corresponding resolution path.
- Connection: Distinguish between timeout, refusal, no route, TLS, and authentication failures. Change one related variable at a time.
- Application: Once an HTTP response arrives, check the website’s status, login state, and application protocol. Don’t attribute every failure to the proxy connection.
When reporting an issue to maintainers, include the client and core versions, operating system, steps to reproduce, operating mode, relevant configuration snippets, and logs from the same request. Before posting, remove subscription URLs, access tokens, passwords, UUIDs, and private domains. Keep error keywords, field names, port relationships, and event order. If you replace addresses, use the same alias for the same object across all log lines.
After the issue is fixed, test the same destination through the same entry point and record which change resolved it. Restore debug to your usual log level. To check configuration fields, see the Configuration Reference. For initial proxy and TUN setup, follow the Getting Started guide step by step.