pnpm/pnpm · error · PnpmError
INVALID_PROXY
INVALID_PROXY
Error message
Couldn't parse proxy URL
What it means
parseProxyUrl normalizes the configured proxy value (https-proxy/proxy settings or environment) by prepending the protocol when the value lacks '://', then parses it with the URL constructor. Any construction failure becomes INVALID_PROXY, with a hint that credentials embedded in the URL must be percent-encoded (everything except the colon between user and password).
Source
Thrown at pnpm11/network/fetch/src/dispatcher.ts:171
opts.ca ||
opts.cert ||
opts.key ||
opts.localAddress ||
opts.strictSsl === false ||
hasClientCertificates(opts.clientCertificates) ||
opts.maxSockets
)
}
function parseProxyUrl (proxy: string, protocol: string): URL {
let proxyUrl = proxy
if (!proxyUrl.includes('://')) {
proxyUrl = `${protocol}//${proxyUrl}`
}
try {
return new URL(proxyUrl)
} catch {
throw new PnpmError('INVALID_PROXY', "Couldn't parse proxy URL", {
hint: 'If your proxy URL contains a username and password, make sure to URL-encode them ' +
'(you may use the encodeURIComponent function). For instance, ' +
'https-proxy=https://use%21r:pas%2As@my.proxy:1234/foo. ' +
'Do not encode the colon (:) between the username and password.',
})
}
}
function getSocksProxyType (protocol: string): 4 | 5 {
switch (protocol.replace(':', '')) {
case 'socks4':
case 'socks4a':
return 4
default:
return 5
}
}View on GitHub (pinned to 6261b7f388)
Solutions
- Percent-encode the username and password in the proxy URL (encodeURIComponent), keeping the literal colon between them — exactly as the error hint describes
- Fix the scheme and shape: http://host:port, https://host:port, or socks5://host:port
- Unset or correct the proxy env vars (HTTPS_PROXY, HTTP_PROXY, ALL_PROXY) and the pnpm config if no proxy is intended
- Where possible, keep credentials out of the URL entirely
Example fix
# before — password contains ! and * unencoded https-proxy=https://use!r:pas*s@my.proxy:1234 # after — percent-encoded userinfo, colon kept literal https-proxy=https://use%21r:pas%2As@my.proxy:1234
Defensive patterns
Strategy: validation
Validate before calling
function isValidProxyUrl (proxy: string, protocol = 'https:'): boolean {
try {
new URL(proxy.includes('://') ? proxy : `${protocol}//${proxy}`)
return true
} catch {
return false
}
}
for (const candidate of [process.env.HTTPS_PROXY, process.env.HTTP_PROXY, config['https-proxy']]) {
if (candidate && !isValidProxyUrl(candidate)) {
// percent-encode userinfo or fix the scheme before running pnpm
}
} Try / catch
try {
createDispatcher(...)
} catch (err) {
if (err instanceof PnpmError && err.code === 'INVALID_PROXY') {
// follow the embedded hint: encode credentials, keep the user:pass colon literal
}
throw err
} Prevention
- Always percent-encode usernames and passwords placed in proxy URLs (encodeURIComponent), keeping only the separating colon literal
- Validate proxy settings from env and config at startup in CI, before the first network call
- Store proxy credentials outside the URL where your tooling allows it
When it happens
Trigger: A proxy value that is not a valid absolute URL after normalization: unencoded reserved characters (!, @, :, /, *) in the userinfo, a broken scheme like 'http//host', or stray whitespace in the setting.
Common situations: HTTPS_PROXY / https-proxy containing a password pasted verbatim from a password manager; CI secrets with special characters; hand-typed proxy URLs missing a scheme or port.
Related errors
- ERR_PNPM_CANNOT_DOWNLOAD_BINARY_OFFLINE
- Redirect location header missing for ${redactUrlCredentials(
- PING_ERROR
- INVALID_NAMED_REGISTRY_URL
- pnpr server /-/pnpr/v0/resolve stream ended without a termin
AI-assisted analysis of pnpm/pnpm@6261b7f388 (2026-08-17).
Data as JSON: /api/errors/acc47800b8563d70.
Report an issue: GitHub.