axios HTTPS proxy not working: httpsAgent, proxy: false and the 407

The worst axios proxy bugs don’t throw. The request just leaves from your own IP, or from a proxy you forgot about. Here is each one, measured.

6 min readTested on axios 1.20 · https-proxy-agent 9.1 · Node 22
An https:// request in axios uses httpsAgent. A proxy agent set on httpAgent is never used, and the request leaves from your own IP.axios.get("https://…") only looks at one of the two agentsaxios.gethttps://httpsAgent: proxy agentused: leaves from a residential exithttpAgent: proxy agentignored: leaves from your own IPAxiosError: Request failed with status code 403…can be the proxy, not the website. statusText tells you which.axios 1.20 · https-proxy-agent 9.1 · Node 22 · October 14, 2026

In short

Put the proxy agent on httpsAgent (not httpAgent) and set proxy: false, so neither axios’s own option nor HTTPS_PROXY takes over. A 403 or 407 can be the proxy refusing you; check err.response.statusText.

httpsAgentproxy: false

We checked every setup against api.ipify.org and compared the answer with our own IP. Two of them never touched the proxy, and neither raised an error:

SetupWhere the request came from
httpsAgent: proxy agent, proxy: falseA residential exit
proxy: { protocol: 'http', host, port, auth }A residential exit
httpAgent: proxy agent, proxy: falseOur own IP: the agent was never used
httpsAgent: proxy agent, HTTPS_PROXY set, no proxy: falseThe HTTPS_PROXY proxy (a 407 with a stale login)
proxy: { protocol: 'https', … }write EPROTO … wrong version number
Fig. 1 — axios 1.20 with https-proxy-agent 9.1 on Node 22, against via.proxies.vision:9000, October 14, 2026.

The agent is on httpAgent

axios picks the agent by the scheme of the URL you request: httpsAgent for https://, httpAgent for http://. Almost everything is https:// today, so an agent on httpAgent does nothing and, with proxy: false, the request goes out directly. Your scraper works, from your own address.

HTTPS_PROXY wins

axios reads HTTP_PROXY, HTTPS_PROXY and NO_PROXY unless you pass proxy: false. With the variable set, our agent was bypassed and the request went to the proxy in the variable, whose login was stale: 407. With an agent, always add proxy: false.

protocol: 'https'

The protocol in axios’s proxy option is how axios talks to the proxy, not to the website. Our proxy port speaks plain HTTP, so 'https' sent a TLS handshake to it and Node failed with EPROTO … wrong version number. The same error in other languages.

When the proxy refuses the tunnel, axios turns its answer into an ordinary AxiosError with that status, both with the built-in option and with https-proxy-agent. It reads exactly like the website refusing you:

407wrong passwordRequest failed with status code 407
403USER-country-usa (a value the proxy can’t read)statusText: Invalid Request
465USER-country-de-city-chicago (no exit)Request failed with status code 465
200USER-country-dea German exit

Proxy or website?

Look at the response. Our gateway’s 403 had statusText “Invalid Request”, a body naming the bad part (Invalid "country") and a single content-length header. A website’s 403 came with its own date, server and content-type headers. 465 is never a website: it is our gateway saying no exit matches your filters.

A key the proxy doesn’t know

-cc-DE, the way some other gateways write a country, isn’t a key on ours. It was ignored and the request came back 200 from Australia. Write -country-de; the other targeting options are on the locations page.

Our rotating port picks a new exit per connection. Whether you get a new IP per request therefore depends on whether the agent reuses its connection:

1 IPnew HttpsProxyAgent(url, { keepAlive: true }), 3 requeststhe connection is reused
3 IPsnew HttpsProxyAgent(url), 3 requestsa new connection each
3 IPsa new agent per requestalways a new connection

For the same IP on purpose, for a login or a checkout, add a session label and use the sticky port 10000: USER-country-de-session-checkout1-lifetime-10.

A setup that works

An axios instance per identity, the agent on httpsAgent, proxy: false, and a retry for dropped exits. Ran as shown.

fetch_ip.mjs
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";

const USER = process.env.PROXY_USER;
const PASS = process.env.PROXY_PASS;

// One agent = one kept connection = one IP. Make a new agent for a new IP.
function proxied(targeting = "") {
  const login = `${encodeURIComponent(USER + targeting)}:${encodeURIComponent(PASS)}`;
  return axios.create({
    httpsAgent: new HttpsProxyAgent(`http://${login}@via.proxies.vision:9000`), // httpsAgent, not httpAgent
    proxy: false, // ignore HTTPS_PROXY and axios's own proxy option
    timeout: 30000,
  });
}

// Residential exits sometimes drop a connection (ECONNRESET): retry on a new one.
// A status from the proxy (407, 403, 465) won't change on a retry.
async function get(url, targeting = "", attempts = 3) {
  for (let i = 1; ; i++) {
    try {
      return await proxied(targeting).get(url);
    } catch (err) {
      if (err.response || i === attempts) throw err;
    }
  }
}

for (let i = 0; i < 3; i++) {
  const { data } = await get("https://ipinfo.io/json", "-country-de");
  console.log(data.ip, data.country, data.org);
}
txt
79.220.1.67 DE AS3320 Deutsche Telekom AG
92.208.79.60 DE AS3209 Vodafone GmbH
212.114.229.147 DE AS8767 M-net Telekommunikations GmbH

Why the retry

In our first run the second request failed with ECONNRESET, “Client network socket disconnected before secure TLS connection was established”: the exit, someone’s home connection, went away. A new agent got a new exit and the request went through. Errors without err.response are worth a retry; a status from the proxy isn’t.

Why does axios ignore my proxy agent?
Most often because the agent is on httpAgent while the URL is https://. axios uses httpsAgent for https:// URLs, so the request goes out directly from your own IP, with no error. Put the proxy agent on httpsAgent.
Do I still need https-proxy-agent with axios?
Not for a plain HTTP proxy: in axios 1.20 the built-in proxy option tunnelled an https:// request correctly in our test. An agent is still the better choice when you want control over connections (one IP per agent) or a SOCKS proxy.
Why do I need proxy: false when I use an agent?
Without it axios also reads HTTPS_PROXY from the environment and uses that proxy instead of your agent. In our test a stale HTTPS_PROXY turned a working agent into a 407. proxy: false makes the agent the only proxy.
Is 'Request failed with status code 403' from the website or from the proxy?
axios reports both the same way. Look at err.response.statusText and headers: our gateway's refusal said 'Invalid Request' with only a content-length header, while a website's 403 carries its own headers (date, server, content-type).
What does 'write EPROTO … wrong version number' mean with an axios proxy?
The proxy was configured with protocol: 'https', so axios spoke TLS to a proxy port that speaks plain HTTP. Use protocol: 'http'; the connection to the website is still encrypted inside the tunnel.

Residential proxies, pay per GB

HTTP and SOCKS5. Country, city and sticky sessions in the username. No subscription.