Two split-tunnel profiles, two private prefixes, and one host that both of them claim. The symptom is rarely a clean failure: a service works on Monday, times out after the second client reconnects, and works again after a reboot. The order you connected the clients in does not decide the outcome, and neither does the order of the rows in the client's UI. Run these checks in order, and stop at the first one that does not hold, because the later ones only make sense once the earlier ones are true.

1. Write down the destination and the source

Start with the exact address the failing request goes to, not the hostname and not the application name. Resolve the name once, note every answer, and pick the one the failing flow actually uses. Then note the local address of the same flow, because the source address can change which policy rule matches and therefore which table is consulted.

A request that goes to one of several A records can fail while a sibling address succeeds, which looks like a flaky tunnel and is really two different paths. If the destination is a name with several answers, test each answer separately before you change anything.

2. Ask the kernel which route it chose

Do not read the route table and infer the answer. Ask the same question the stack asks, with the same source address: ip route get 10.20.4.10 from 10.8.0.2 on Linux, or Find-NetRoute -RemoteIPAddress 10.20.4.10 in PowerShell. The output names the route that would actually be used, which is often not the one you expected from reading the table.

Among routes that match, the more specific prefix normally wins: a /24 beats a /16 for an address inside both. Between matches of equal length, the lower metric wins, and a route installed on a link that is down is skipped. Two tunnels pushing the same /24 with the same metric is a different case: the kernel keeps both routes and selects among them, so the outcome can alternate instead of following the order the clients connected in. That is exactly the situation that produces the Monday-works-Tuesday-fails pattern, and reconnecting in a different order does not change it.

3. Check whether a policy rule redirected the lookup

Before the route table is consulted, the kernel walks its policy rules. A rule can send traffic from a given source, user, or firewall mark to a different table entirely, so the winning prefix in the main table may never be consulted for that flow. ip rule show lists them in evaluation order, and ip route show table 100 shows what the selected table actually contains.

Two traps live here. A rule that points at an empty table produces a lookup that falls through to the next rule, so the rule appears to do nothing. The other is the priority number itself: rules are read in ascending order, and the built-ins are 0 local, 32766 main and 32767 default. A rule numbered below 32767 is consulted before the catch-all default rule. A rule numbered above 32767 sits behind it and is only reached when no earlier table answers, which a normal default route in main prevents, so in practice it is never reached and silently does nothing while looking installed. If the client wrote a rule and a route, check both, and check them again after a reconnect, since a rewritten profile can add a second rule with a different priority.

4. Separate a routing tie from a duplicated address plan

Sometimes the prefix is not the problem at all. Two sites both using 192.168.1.0/24 mean the same address identifies two different hosts, and no route can tell them apart. A host route to one of the two answers only works until the other site answers for the same name, and then the exception silently becomes the bug.

The tell is that the destination address is identical on both paths and only the intended owner differs. That is an address-plan decision, not a routing tweak: renumber one side, put one side behind a translating gateway, or reach the second site through a proxy that resolves its own names. Lowering a default route or stacking host exceptions just moves the collision around.

5. Confirm the resolver agrees with the route

A name that resolves to the wrong private address produces every symptom of a routing conflict and none of its causes. Compare the answer the host receives with the address the destination actually uses, and check which resolver answered. If the tunnel pushes a resolver, the client should install it for the flows that use the tunnel; if it does not, the host keeps asking the local resolver, which may answer from a search domain or a cached record.

Query the resolver directly and note the server that replied. A cached answer with a short TTL can also explain why the first request after a reconnect behaves differently from the fifth.

6. Reconnect, inspect the applied state, then test both flows

After a correction, reconnect and inspect what the client actually installed rather than trusting the profile editor. Read the rules, the tables, and the resulting ip route get answer again. A second client can reinstall its own route on connect and recreate the conflict, which is why the state check has to happen after the last client connects, not before.

Test two flows, not one: the request that used to fail, and a resource that is supposed to use the other tunnel. Moving all private traffic onto one connection will make the first test pass while breaking the second, and only a paired test catches that. Record each exception you keep, with the destination and the reason, so the next person can tell a deliberate host route from a leftover one.

Mikanda mikatakata