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

  1. Percent-encode the username and password in the proxy URL (encodeURIComponent), keeping the literal colon between them — exactly as the error hint describes
  2. Fix the scheme and shape: http://host:port, https://host:port, or socks5://host:port
  3. Unset or correct the proxy env vars (HTTPS_PROXY, HTTP_PROXY, ALL_PROXY) and the pnpm config if no proxy is intended
  4. 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

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


AI-assisted analysis of pnpm/pnpm@6261b7f388 (2026-08-17). Data as JSON: /api/errors/acc47800b8563d70. Report an issue: GitHub.