Your Mac downloads a policy script and then asks that script which intermediary a request should use, while the tunnel only decides how the chosen hop is reached. Both answers land on the same socket, so a request that fails after both of them succeeded looks like one fault when it is two. Separating the download from the selection, and the selection from the route, is most of the work in these tickets. The order below follows what macOS actually does, with the checks that make each stage visible.

Where the PAC address and the proxy diverge

An address such as https://config.corp.example/proxy.pac names a document to download, and that document names a server to send traffic through. Pasting the URL into a proxy host field asks the client to open a proxy connection to a file server that never listens for one. Inside the file is a function the client calls per request, and its return value is the next hop for that single destination. That indirection explains why two machines on the same network service can behave differently while both hold the correct URL. It also explains why a policy change takes effect without anyone touching the proxy itself.

Read the script before interpreting anything downstream, because the rules inside it carry the organisation's exceptions and the order they apply in. An early broad range can shadow a later internal suffix, and a host that should obviously bypass the proxy keeps using it. When somebody insists the policy is wrong, the script is the only place that claim gets settled.

The script has to be fetched before it decides anything

Downloading the policy needs a name resolved and a route to whatever serves the file, and a connected tunnel implies neither. If the host resolves only through private DNS, the resolver in use at that moment decides whether the download can begin. If the host sits on a private range, the route has to exist from this machine rather than from a colleague's laptop. A copy cached during an earlier session hides all of this until the cache expires or the machine restarts.

Run the three checks below in order and stop at the first failure, because the stages do not share a cause. Between them they show whether the policy is configured, whether it is reachable, and what it returns.

scutil --proxy
networksetup -getautoproxyurl "Wi-Fi"
curl -sS -o /dev/null -w "%{http_code}\n" https://config.corp.example/proxy.pac

The first command prints the proxy dictionary for the active service, including any auto-configuration URL the system is holding. The second reports the URL attached to one named service, which matters on a laptop that moves between Wi-Fi and Ethernet. The third fetches the file without rendering it, so a 404, a timeout and a resolver failure stay distinguishable. If that last command returns the script while applications still fail, the problem has already moved past retrieval.

What a DIRECT answer actually skips

The PAC specification gives the client a small vocabulary, and DIRECT is one word of it. The word tells the client to skip the proxy for that request and says nothing about which interface the socket then uses. A direct socket on a full tunnel still leaves through the VPN and still shows the tunnel's exit address to the destination.

Reading DIRECT as outside the VPN is the mistake that sends people to the wrong settings panel. The mirror image is just as common, because a private proxy can be reached over a split route while the rest of the machine stays off the tunnel. What the destination reports then belongs to the proxy's own egress, which may sit in another country. Writing the expectation for one internal host and one public host exposes this quickly, since the script often answers the two differently. Once you know which hop produced the address, the report stops being mysterious.

Three failures that surface as one error page

The policy may fail to download, the chosen proxy may be unreachable, and a request that arrives at the service may still be refused there. All three arrive as a timeout or a generic error page, and none of them names the stage that broke. Capturing the decision next to the error is what separates them. The two probes below test the hop the script selected, one for each branch it can return.

curl -v --max-time 8 http://proxy.corp.example:8080/
curl -v --max-time 8 https://intranet.corp.example/

A completed connection to the proxy moves the question to authentication or to the proxy's own policy, which has a different owner. A completed connection to the internal host with no proxy in the path rules out the route and points at the policy. Both commands ignore the macOS proxy dictionary unless the shell exports proxy variables, so clear those first. Neither probe proves the other, which is why one error page misleads for so long.

What to hand over with the ticket

Send the active network service, the PAC URL, the evaluation result for the failing host, and the stage where the error appeared. Those four let the next person reproduce the decision instead of guessing which layer was involved. Add the tunnel state at the moment of the test, because a result captured before a reconnect is stale. Keep the script revision as well, since the policy file changes without notice and yesterday's answer may no longer be current.

Record how the client behaves when the script cannot be fetched, because implementations differ and the proxy decision is not a device-wide kill switch. Some fall back to a direct connection and others fail closed, and that difference changes whether an outage looks like a broken proxy or like working policy. Confirm the behaviour for the exact client and version before relying on it during an incident.

Pennadoù liammet