Debugging a PAC file in Chrome, Edge and Firefox

Published

When a PAC file misbehaves in production, the question is always the same. Which proxy did this browser choose for this URL, and why? Chromium-based browsers and Firefox can both tell you, if you know where to look.

Before you open a browser, paste the file into the online PAC file tester. It shows per URL and engine which line decided the result, and it catches most logic errors in seconds. Use the browser when you need to know what one real client did.

Items marked (expert) are practitioner knowledge that has not been verified in our lab yet. Everything else is either documented by the vendor or used in our lab runs.

Chrome and Edge (Chromium)

Isolated test profile. Start a separate browser instance that uses your PAC and nothing else:

chrome --user-data-dir=/tmp/pac-test --proxy-pac-url=https://pac.corp.example/proxy.pac \
       --log-net-log=/tmp/pac-test/netlog.json --net-log-capture-mode=Everything

These are the flags our lab uses to drive Chrome and Edge (source: lab, 2026-10-04). Use the Edge executable for Edge.

Record a NetLog in a running browser. Open chrome://net-export/, click Start Logging To Disk, reproduce the problem in another tab, then click Stop Logging. Keep the net-export tab open while recording. Open the file in the NetLog viewer (source: doc, chromium.org, checked 2026-10-06). In Edge the page is edge://net-export/ (expert).

What to look for:

  • the proxy list the PAC returned for the request, and which entry was used;
  • alert() messages from your PAC. Chromium sends them to the NetLog, not to a dialog (source: code, verified 2026-10-04);
  • whether the PAC fetch itself failed. Without a usable PAC, Chromium connects directly unless a mandatory-PAC policy is set (PAC-D010).

chrome://net-internals/#proxy shows the effective proxy settings and lets you re-apply them after you change the PAC (expert).

Chrome-specific traps:

  • For https:// URLs Chrome passes only https://host:port/ to the script; path and query are removed (source: code, verified 2026-10-04). A rule on the path of an https URL never matches.
  • Name resolution is asynchronous, and the script may run again once a DNS answer arrives (expert). alert() output can therefore appear twice.

Firefox

Test profile. In a fresh profile, set these prefs in about:config or in user.js:

user_pref("network.proxy.type", 2);   // 2 = automatic proxy configuration URL
user_pref("network.proxy.autoconfig_url", "https://pac.corp.example/proxy.pac");

Proxy logging. Start Firefox with the MOZ_LOG environment variable to log proxy resolution:

MOZ_LOG=proxy:5,timestamp MOZ_LOG_FILE=/tmp/pac-test/moz.log firefox -profile /tmp/pac-test

The prefs and the log module are what our lab uses for Firefox (source: lab, 2026-10-04). The same modules can be switched on at runtime in about:logging (expert).

alert() output goes to the browser console (source: doc, MDN, checked 2026-10-06).

Firefox-specific traps:

  • With the default settings Firefox removes the path and query for every scheme, plain http:// included (source: code, verified 2026-10-04).
  • dnsResolve blocks the PAC thread while it waits (source: code, verified 2026-10-04). A slow resolver slows every request; see DNS in PAC files.
  • The Microsoft *Ex functions do not exist in Firefox. Calling them throws, and the request goes direct (PAC-K003).

Traps in every browser

  • Caching. The browser keeps the PAC for an engine-specific time when the server sends no Cache-Control (PAC-D003). While debugging, restart the test profile after each change. In production, send max-age of an hour or less during a change.
  • Errors look like success. An exception or a missing return makes Chromium and Firefox connect directly (source: code, verified 2026-10-04). If “everything works” but the proxy logs are empty, check for that first.
  • Remove debugging alerts. alert() calls in a production PAC write to logs on every request.

Before you debug in a browser

Most “the browser ignores my PAC” reports turn out to be one of the top 20 PAC mistakes. Run the file through the tester first, with the failing URL as a test URL. If all engine profiles agree and the browser still differs, the NetLog or MOZ_LOG shows why.

Frequently asked questions

Where does alert() output from a PAC file go?

In Chromium (Chrome, Edge) alert() in a PAC file writes to the NetLog, not to a dialog. In Firefox it goes to the browser console. pacparser prints it to the console.

How do I test a PAC file in Chrome without changing the system proxy?

Start Chrome with a separate profile and the --proxy-pac-url flag, for example chrome --user-data-dir=/tmp/pac-test --proxy-pac-url=https://pac.corp.example/proxy.pac. Only that browser instance uses the PAC.

Why does my PAC change not take effect?

Browsers keep the downloaded PAC for a while. Without a Cache-Control header the engine decides how long. Serve the file with an explicit max-age and reload the proxy settings or restart the browser while testing.