When npm cannot reach its registry, the error often ends with a paragraph about proxies. That paragraph comes with some errors and not with others. The line that names the problem is the one that starts with npm error code.
We tested how npm handles a proxy on 27 September 2026, with npm 11.8.0 and with npm 10.9.3, the version bundled with Node 22.19. The proxies ran on our own machine. The registry was a made-up host that only those proxies could reach, so every request either went through a proxy or failed at once. We ran 42 setups on both versions, twice, and got the same results every time. More tests covered the npm config commands, a proxy that never answers and the real registry. npm 12 was not run, but it ships the same proxy code, as How we tested explains.
The short version:
- Set
https-proxyto an address that starts withhttp://. npm useshttps-proxywhen it is set andproxyotherwise, for every request. HTTP_PROXYdoes not cover the registry. Forhttps://addresses npm readsHTTPS_PROXY, and--proxy=falsedoes not switch that off.npm config getshows only npm's own settings. It printsnullwhileHTTPS_PROXYis set, and it refuses to print an address that holds a password.- With SOCKS, write
socks5h://. Withsocks5://, npm looks up the registry name on your own machine first. - For a company certificate, use
NODE_EXTRA_CA_CERTS. Thecafilesetting replaces npm's whole list of trusted authorities.
Read the npm error code line
Since npm 10.6.0, released in April 2024, every error line starts with npm error. Older versions printed npm ERR!. When npm cannot find the registry, npm 11.8.0 ends like this:
npm error code ENOTFOUND
npm error syscall getaddrinfo
npm error errno ENOTFOUND
npm error network request to https://registry.lab.test/lab-pkg failed, reason: getaddrinfo ENOTFOUND registry.lab.test
npm error network This is a problem related to network connectivity.
npm error network In most cases you are behind a proxy or have bad network settings.
npm error network
npm error network If you are behind a proxy, please make sure that the
npm error network 'proxy' config is set properly. See: 'npm help config'
In our tests the paragraph about proxies came with two codes, ENOTFOUND and ECONNRESET. After ECONNREFUSED, npm printed its last two lines below a stack trace. The login error, the certificate errors and the rest came without it. Read the code line. This is what caused each one in our tests:
ENOTFOUND: no proxy was used, and the name did not resolve. Sethttps-proxy.E407: the proxy wants a login. Add the login to the address.ECONNRESET: the proxy cut the connection. Test the proxy on its own.ECONNREFUSED: nothing listens at the proxy address. Fix or remove the setting.EPROTO:https://in front of a plain proxy. Writehttp://.EINVALIDPROXY: an address withouthttp://. Add it.FETCH_ERROR: a SOCKS proxy wants a login. Add the login to the address.- No error and no end: the proxy never answers. Stop npm and test the proxy.
The certificate codes have their own section below.
ENOTFOUND: npm went direct
getaddrinfo ENOTFOUND means the name lookup failed. Node's documentation calls it "a DNS failure". In our tests it meant npm had not used a proxy at all. Either none was set, or only HTTP_PROXY or ALL_PROXY was set, or a noproxy entry matched, or the proxy address started with socks5:// or socks4://. On a network where only the proxy reaches the internet, you get this error until npm uses the proxy. The next section shows which settings count.
E407: the proxy wants a login
npm error code E407
npm error 407 Proxy Authentication Required - GET https://registry.lab.test/lab-pkg
npm printed these two lines and the path of its log, and nothing else. The fix is a login in the proxy address. Our guide to 407 Proxy Authentication Required covers the same error in other tools.
ECONNRESET: something cut the connection
One of our proxies cut the connection when npm asked for a tunnel. Another cut it during the encrypted handshake that follows. Both gave the same line, followed by the paragraph about proxies:
npm error network request to https://registry.lab.test/lab-pkg failed, reason: read ECONNRESET
Node's documentation describes the code as "A connection was forcibly closed by a peer." npm cannot tell you which step failed, or whether a proxy did it. Test the proxy address outside npm first:
curl -v -x http://proxy.example.com:3128 https://registry.npmjs.org/
If curl gets through and npm does not, compare the settings in the next section. A popular Stack Overflow answer suggests switching the registry to http://. Today the registry answers every plain http:// request with a redirect to https://: we checked the registry root, a package and a tarball. So the switch no longer avoids the encrypted connection. It adds an unencrypted first request that the network can read and change, and it hides the cause.
ECONNREFUSED: nothing at that address
The line to read is connect ECONNREFUSED 127.0.0.1:<port>, with the address and port from your setting. That address is the proxy's, and nothing listened there. npm printed a stack trace and the last two lines of the proxy paragraph.
An address on 127.0.0.1 points at your own machine: a program there was meant to answer, and none did. npm takes its proxy from its own settings or, for the https:// registry, from HTTPS_PROXY, so the old address sits in one of those. Checking shows how to find it. How to turn off a proxy covers the proxy settings of the system itself.
A proxy that never answers
One of our proxies accepted the connection, read npm's request for a tunnel, and stayed silent. npm printed nothing and did not stop. With the default timeouts, npm 11.8.0 and npm 10.9.3 were both still waiting after 10 minutes. That is twice the default fetch-timeout of 5 minutes. Setting fetch-timeout to 5 seconds changed nothing within a minute.
npm's code explains why. fetch-timeout becomes a timer on the connection, and npm starts it only after the proxy has opened the tunnel. The step before that has no limit: its connection timeout is set to 0. If npm hangs without an error, stop it with Ctrl+C and test the proxy with curl as above.
We did not produce ETIMEDOUT, because our tests never left the machine. Node's documentation describes it as "A connect or send request failed because the connected party did not properly respond after a period of time." The same curl test shows whether the proxy address answers at all.
EPROTO and EINVALIDPROXY: the start of the address
With https:// in front of an ordinary proxy, npm tried to open an encrypted connection to the proxy itself. The proxy answered in plain text, and npm stopped with EPROTO and wrong version number. Write http:// for https-proxy too, unless your proxy's documentation says it takes encrypted connections.
Without any scheme, as in localhost:8080, npm stopped at once:
npm error code EINVALIDPROXY
npm error Invalid protocol `localhost:` connecting to proxy ``
npm read localhost: as the scheme. Put http:// in front.
Which setting npm uses
npm has two proxy settings, https-proxy and proxy, and it also reads the environment. This is what reached our proxy when npm fetched from an https:// registry:
| Setup | Through the proxy? |
|---|---|
https-proxy (flag or .npmrc) | Yes |
proxy only | Yes |
HTTPS_PROXY | Yes |
HTTP_PROXY only | No, npm went direct |
ALL_PROXY only | No, npm went direct |
HTTPS_PROXY with proxy=false | Yes, still |
noproxy naming the registry | No, skipped |
noproxy=lab.test | No, skipped |
noproxy=*.lab.test | Yes, still |
NO_PROXY=* | Yes, still |
npm's documentation says proxy is for http requests and that HTTP_PROXY is honoured for https requests. Neither matched what npm did, and the code explains both. npm hands one proxy to every request: https-proxy when it is set, and proxy otherwise. Only when both are empty does npm read the environment. For an https:// address it then reads HTTPS_PROXY alone, in any letter case. A setting of false counts as empty, which is why --proxy=false did not stop HTTPS_PROXY.
noproxy takes a list separated by commas. npm compares whole parts of the host name, starting from the right, so lab.test covered registry.lab.test. A star is not a wildcard in npm: *.lab.test and NO_PROXY=* changed nothing. List the domains themselves:
npm config set noproxy "localhost,127.0.0.1,corp.example.com"

Set, check and remove a proxy
Set both keys to the same address. They land in your user .npmrc, which is ~/.npmrc, or C:\Users\<you>\.npmrc on Windows:
npm config set https-proxy http://user:pass@proxy.example.com:3128
npm config set proxy http://user:pass@proxy.example.com:3128
Each command writes one line into the file. In our test, npm config set proxy http://proxy.example.com:3128 and npm config set https-proxy http://alice:p%40ss@proxy.example.com:3128 left exactly this:
proxy=http://proxy.example.com:3128
https-proxy=http://alice:p%40ss@proxy.example.com:3128
You can also write these lines into the file yourself. A project can carry its own .npmrc in its folder, and npm also has a global one. npm config list shows each value under the file it came from. It showed our password as ***. npm config list -l adds every default, 186 lines in npm 11.8.0.
npm config get can mislead in two ways:
npm config get https-proxyprintsnullwhen the proxy comes fromHTTPS_PROXY. It shows npm's own settings only.- When the address holds a password,
npm config getrefuses to print it: "The https-proxy option is protected, and cannot be retrieved in this way". Read it withnpm config list, or open the.npmrcfile.
The environment needs its own check. Since npm 11.8.0, released in January 2026, npm config list shows proxy variables in a block called environment-related config. npm 10.9.3 does not show them. That block printed our test password in plain text, while the same password from .npmrc showed as ***. Look at it before you paste the output anywhere. You can also ask the shell:
- PowerShell:
Get-ChildItem Env:*proxy* - Command Prompt:
set | findstr /i proxy - macOS and Linux:
env | grep -i proxy
A variable named npm_config_https_proxy is an npm setting in the environment. npm config get and npm config list both show it.
To remove the proxy:
npm config delete https-proxy
npm config delete proxy
npm config rm does the same. Once the last setting was gone, npm deleted the .npmrc file. npm config set proxy false does not remove anything: it writes proxy=false into the file, and a proxy in HTTPS_PROXY stays in use, as the table shows. Remove the variable as well. For the current window, run Remove-Item Env:HTTPS_PROXY in PowerShell, set HTTPS_PROXY= in Command Prompt with nothing after the equals sign (a space there sets the variable to a space), or unset HTTPS_PROXY https_proxy elsewhere. For good, delete it in the system settings or your shell profile.
A login in the proxy address
npm takes the login from the address, http://user:pass@proxy.example.com:3128. In our tests it sent the login with its first request to the proxy, as Basic authentication.
A password with @ worked in both forms, written as %40 and left as it is. The raw form works because the last @ ends the login. Other characters need the percent form. In Node's URL parser, which npm's proxy code uses, a raw # broke the whole address, while %23 worked. Node prints the percent form for you:
node -e "console.log(encodeURIComponent('p@ss#1'))"
That prints p%40ss%231. A missing or wrong login gives E407.
We did not test proxies that accept only Windows logins (NTLM or Kerberos).
SOCKS proxies
npm accepts SOCKS addresses in https-proxy, proxy and HTTPS_PROXY. The letters after socks decide who looks up the registry's name:
socks5h://,socks://andsocks4a://: npm passes the name to the proxy. Our proxy receivedregistry.lab.test, and all three worked.socks5://andsocks4://: npm looks the name up on your machine first.registry.lab.testexists only behind our proxy, so npm stopped withENOTFOUNDbefore it contacted the proxy. With a name that does resolve here,localhost, the proxy received an address instead of a name.
The code of the SOCKS agent that npm uses says it in a comment: "Client-side DNS resolution for "4" and "5" socks proxy versions." On a network where your machine cannot look up outside names, only the forms that pass the name get through: socks5h://, socks:// and socks4a://. With socks5://, your own DNS server also sees every host npm contacts.
npm config set https-proxy socks5h://user:pass@proxy.example.com:1080
A login in the address worked, with @ written as %40. When our SOCKS proxy wanted a login and got none, npm printed FETCH_ERROR and "Received invalid Socks5 initial handshake (no accepted authentication type)". Our SOCKS5 guide explains the protocol.
Certificate errors from an inspecting proxy
Some company proxies open HTTPS to look inside it, then sign the connection again with the company's own certificate authority. npm does not trust that authority. The error code depends on what the proxy sends along with its certificate:
- Only its own certificate:
UNABLE_TO_VERIFY_LEAF_SIGNATURE, "unable to verify the first certificate". - Its certificate and the company root:
SELF_SIGNED_CERT_IN_CHAIN, "self-signed certificate in certificate chain". - Its certificate and an intermediate:
UNABLE_TO_GET_ISSUER_CERT_LOCALLY, "unable to get local issuer certificate".
OpenSSL's documentation fits each shape. For the second one, it says the chain "could be built up using the untrusted certificates but no suitable trust anchor (which typically is a self-signed root certificate) could be found in the trust store."
All three have one fix: trust the company's root certificate. Ask IT for it, or export it from the system certificate store as a PEM file. Two settings take it, and they behave differently:
NODE_EXTRA_CA_CERTSadds the root to Node's built-in list, for npm and every other Node program. With it, npm worked through the inspecting proxy and through a plain proxy to the normal registry.npm config set cafilereplaces npm's whole list with the file. It fixed the inspecting proxy. With only the company root in the file, though, npm rejected the normal registry. In our lab, whose registry sent only its own certificate, the code wasUNABLE_TO_VERIFY_LEAF_SIGNATURE. Against the real registry, registry.npmjs.org, with no proxy in between, npm 11.8.0 and 10.9.3 both stopped withUNABLE_TO_GET_ISSUER_CERT_LOCALLY. That is the position of a laptop that leaves the company network, and it is the same code an inspecting proxy can give. When it appears away from the company network, check whethercafileis set before you look for a proxy.
npm's own documentation says a specific certificate in its ca setting means you "trust only that specific signing authority". Setting both does not help either. With cafile set, npm ignored the root we had put in NODE_EXTRA_CA_CERTS. Node's documentation says why: "Neither the well known nor extra certificates are used when the ca options property is explicitly specified". NODE_EXTRA_CA_CERTS alone is the simpler choice. Set it once for your user:
setx NODE_EXTRA_CA_CERTS C:\certs\company-root.pem
On macOS and Linux, put export NODE_EXTRA_CA_CERTS="$HOME/certs/company-root.pem" in your shell profile. Node reads the variable only when a process starts, so open a new terminal.
--strict-ssl=false also got npm through the inspecting proxy, by switching off certificate checks for every request to the registry. Use it once to confirm the diagnosis, then set up the certificate.
pnpm and Yarn
pnpm still reads proxy, https-proxy and http-proxy from .npmrc. Its current documentation lists httpsProxy, httpProxy and noProxy as settings for pnpm-workspace.yaml. One change matters for company setups: since pnpm 11.5.3, a proxy address with a placeholder such as ${HTTPS_PROXY} in the project .npmrc at the workspace root "is ignored, and pnpm prints a warning", in the words of its documentation.
Yarn 2 and later read httpProxy, httpsProxy, httpsCaFilePath and enableStrictSsl from .yarnrc.yml. We tested neither pnpm nor Yarn.
npm's proxy is not your code's proxy
Setting npm's proxy changes nothing for the programs npm installs. A Node script that calls fetch or axios opens its own connections and never reads .npmrc. Our Node.js proxy guide covers that side, tested the same way, and the guides to node-fetch and axios go into those two clients. For Git behind the same proxy, see Git proxy settings and errors.
How we tested
On 27 September 2026 we ran three tests on one Windows machine with Node 22.19, using npm 11.8.0 and npm 10.9.3. Each npm run got an empty user and global .npmrc, a new cache and no retries, so nothing from the machine's own setup could interfere.
- 42 proxy setups. npm asked a registry on our machine, named
registry.lab.test, for a package. That name exists nowhere else, so npm could reach the registry only through one of our proxies, and each proxy logged what it received. We ran every setup twice on both versions. All 84 results matched between the runs, and both versions behaved the same. - The config commands. 21
npm configcommands per version against a throwaway.npmrc, run twice. - The silent proxy. npm against a proxy that never answers, with a 10-minute limit, run twice.
- The real registry.
npm view left-pad versionagainst registry.npmjs.org with no proxy, with a company root incafile, inNODE_EXTRA_CA_CERTSand in both, plus plainhttp://requests to the registry, run twice.
The certificate authorities were made for the tests and deleted afterwards.
npm 12 was not run. Version 12.0.0 came out on 8 July 2026, and 12.1.0, the latest, on 22 September. We compared the proxy code inside the published packages: the file that sets up the proxy is byte for byte the same in npm 10.9.3, 11.8.0 and 12.1.0. In 12.1.0 the step that asks the proxy for a tunnel still has no time limit, so the results above should hold there too.
Sources
- npm CLI: the config definitions, the config command, the config documentation, and the changelogs for 10.6.0 and 11.8.0, read 27 September 2026.
- npm's network code: @npmcli/agent, npm-registry-fetch and minipass-fetch, read 27 September 2026, and the same agent inside the published npm 10.9.3, 11.8.0 and 12.1.0 packages.
- npm's releases and Node's release index, read 27 September 2026.
- The socks-proxy-agent source, read 27 September 2026.
- Node.js documentation: system errors, NODE_EXTRA_CA_CERTS and the ca option of TLS, read 27 September 2026.
- OpenSSL certificate verification errors, read 27 September 2026.
- pnpm: .npmrc and settings. Yarn: .yarnrc.yml settings. Read 27 September 2026.


