# Lab: Axios proxy not working

The scripts and recorded results behind the ipvolt guide
[Axios Proxy Not Working: 16 Causes and Fixes (Tested)](https://ipvolt.com/guides/fix-axios-proxy-not-working).

Recorded on 11 November 2026 on macOS 26.5.1 (arm64) with the official Node.js tarballs v24.22.2 and
v26.13.0, Axios 1.12.2, 1.19.0, 1.20.0, 1.21.0 and 1.21.1 (the main versions), Axios 1.13.6, 1.15.0,
1.16.0, 1.16.1 and 1.18.1 (a sweep to find where behaviour changed), https-proxy-agent 9.1.0,
http-proxy-agent 9.1.0 and socks-proxy-agent 10.1.0. Every request stays on 127.0.0.1. No proxy
account was used: `labuser`, `labpass` and `p@ss/w0rd#1` are placeholders for the lab's own proxies.

## How a result is decided

Each case runs in a fresh process with one Node binary and one Axios version. The lab proxies record
every request they receive and the local port of the socket they open to the target. The targets
record the port each request came from.

- **through proxy**: a proxy logged the request and the target saw that proxy's socket.
- **bypassed silently**: the request succeeded, the target saw the client directly, no proxy logged anything.
- **partly bypassed**: one hop of a redirect went through the proxy and another went direct.
- **never settled**: no response and no error 15 seconds after the request, with `timeout: 5000` set. The lab then kills the process.
- **error**: the request rejected; the record holds the name, code, message and status.

## Files

| File | What it does |
| --- | --- |
| `setup.sh` | Installs each Axios version with the three agent packages under `work/axios-<version>/`. |
| `servers.mjs` | The lab servers: an HTTP proxy with CONNECT and optional Basic authentication, a SOCKS5 proxy, a proxy that closes or never answers, an HTTPS target that speaks HTTP/2 and HTTP/1.1, and an HTTP target. `target.test` redirects `/redirect` to `other.test`. |
| `preload-dns.mjs` | Client-side stand-in for an `/etc/hosts` entry: `target.test` and `other.test` resolve to 127.0.0.1. It does not touch Axios or any agent. `proxy-only.test` is known to the proxies only. |
| `cases.mjs` | The 124 cases: environment variables, Node flags and the request of each. |
| `case.mjs` | Runs one case and prints one JSON line. Sets `axios.defaults.timeout = 5000`. |
| `run.mjs` | `node run.mjs <node binary> <axios version>`: starts the servers, runs every case one at a time and writes `results/node-<version>-axios-<version>.json`. Creates a throwaway CA under `work/certs` with `openssl`. |
| `build-results.py` | Merges those files into `results.json` and `RESULTS.md`. |
| `results.json` | All 1,290 records: 124 cases on 10 Axios versions, one record per case and version, or two where the Node versions differ (the fetch adapter cases, where Node 26 negotiated HTTP/2). Ports are replaced by letters such as `<T>`. |
| `RESULTS.md` | The case-by-version table. |
| `examples/` | The scripts shown in the guide, with placeholders (`proxy.example:8080`, `https://example.com/`). |
| `run-examples.mjs` | Swaps the placeholders for the lab's proxy and target, runs each example on each Node and Axios version and writes `examples.json`. The guard test runs unchanged, once with `client.mjs` and once with `client-broken.mjs`. |
| `build-outputs.py`, `outputs/` | One text file per example and Axios version: the script's output, then what the proxy and the target logged. |

## Run it

```sh
# Unpack the official tarballs from https://nodejs.org/dist/, then:
PATH=/path/to/node-v24.22.2/bin:$PATH sh setup.sh
for version in 1.12.2 1.13.6 1.15.0 1.16.0 1.16.1 1.18.1 1.19.0 1.20.0 1.21.0 1.21.1; do
  node run.mjs /path/to/node-v24.22.2/bin/node "$version"
  node run.mjs /path/to/node-v26.13.0/bin/node "$version"
done
python3 build-results.py
node run-examples.mjs /path/to/node-v24.22.2/bin/node,/path/to/node-v26.13.0/bin/node 1.12.2,1.19.0,1.20.0,1.21.0,1.21.1
python3 build-outputs.py
```

It needs `openssl`, `python3` and access to the npm registry for `setup.sh`. It installs old Axios
releases on purpose, and `npm audit` flags them. Do not copy those versions into an application.

`examples/ip-check.mjs` is the only script that would contact a public service (an IP-echo URL) when
run as written. The lab runs it against the local target instead, so no public IP is recorded here.

## Limits

Loopback only: no real proxy service, no latency, no TLS to the proxy itself, no browser. The lab
proxy answers `400` to an `https://` URL sent without CONNECT; another proxy may answer differently.
The "never settled" cases were watched for 15 seconds, not longer.
