garrytan/gstack · error · ProxyConfigError

invalid proxy URL — bad port

Error message

invalid proxy URL — bad port

What it means

Thrown by parseProxyConfig when the port is not a valid integer in 1..65535. The port comes from url.port if present, otherwise a scheme default (80 for http, 443 for https, 1080 for socks5). An explicit out-of-range or non-numeric port is refused.

Source

Thrown at browse/src/proxy-config.ts:74

  if (scheme !== 'socks5' && scheme !== 'http' && scheme !== 'https') {
    throw new ProxyConfigError(
      'use socks5://, http://, or https://',
      `unsupported proxy scheme '${scheme}'`,
    );
  }

  if (!url.hostname) {
    throw new ProxyConfigError(
      'expected scheme://[user:pass@]host:port',
      `invalid proxy URL — missing host`,
    );
  }

  const port = url.port
    ? parseInt(url.port, 10)
    : (scheme === 'http' ? 80 : scheme === 'https' ? 443 : 1080);
  if (!Number.isInteger(port) || port <= 0 || port > 65535) {
    throw new ProxyConfigError(
      'expected scheme://[user:pass@]host:port',
      `invalid proxy URL — bad port`,
    );
  }

  const urlHasUser = !!url.username;
  const urlHasPass = !!url.password;
  const envHasUser = !!opts.envUser;
  const envHasPass = !!opts.envPass;
  const urlHasCreds = urlHasUser || urlHasPass;
  const envHasCreds = envHasUser || envHasPass;

  // D9 (codex correction): refuse on mixed sources. Silent override is a
  // debugging trap — when a stale BROWSE_PROXY_USER from a prior session
  // wins over a fresh --proxy URL, the user can't tell why.
  if (urlHasCreds && envHasCreds) {
    throw new ProxyConfigError(
      'unset BROWSE_PROXY_USER/PASS or remove user:pass@ from --proxy',

View on GitHub (pinned to 94993f7401)

Solutions

  1. Use a port in 1..65535 (common defaults: 1080 for socks5, 8080/3128 for http)
  2. Omit the port entirely to use the scheme default (80/443/1080)
  3. Double-check the proxy server's actual listening port with its operator or `ss -tlnp`
  4. Validate: `node -e "const p=+process.argv[1]; console.log(Number.isInteger(p)&&p>0&&p<=65535)" <port>`

Example fix

# before
BROWSE_PROXY_URL=socks5://host:99999  # throws

# after
BROWSE_PROXY_URL=socks5://host:1080
Defensive patterns

Strategy: validation

Validate before calling

function isValidPort(s: string): boolean {
  try {
    const u = new URL(s);
    const port = u.port ? parseInt(u.port, 10)
      : (u.protocol === 'http:' ? 80 : u.protocol === 'https:' ? 443 : 1080);
    return Number.isInteger(port) && port > 0 && port <= 65535;
  } catch { return false; }
}

if (!isValidPort(proxyUrl)) {
  throw new Error('Proxy port must be an integer in 1..65535');
}

Type guard

function isIntegerPort(p: number): boolean {
  return Number.isInteger(p) && p > 0 && p <= 65535;
}

Try / catch

try {
  parseProxyConfig(opts);
} catch (e) {
  if (e instanceof ProxyConfigError && /bad port/.test(e.message)) {
    console.error(`${e.message}. ${e.hint}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a proxy URL with port 0, a negative port, a port above 65535, or a non-numeric string in the port position.

Common situations: Typo in the port number (e.g., 99999); copy-paste truncation that left a partial port; ephemeral port picked out of range; confusion between display port and actual listening port.

Related errors


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/ba43fb9c1144c8af. Report an issue: GitHub.