garrytan/gstack · error · ProxyConfigError

invalid proxy URL — missing host

Error message

invalid proxy URL — missing host

What it means

Thrown by parseProxyConfig when the URL parses but has an empty hostname (e.g., socks5://:1080 or socks5:///path). Without a host there is nothing to connect to.

Source

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

  try {
    url = new URL(opts.proxyUrl);
  } catch {
    throw new ProxyConfigError(
      'expected scheme://[user:pass@]host:port',
      `invalid proxy URL — could not parse`,
    );
  }

  const scheme = url.protocol.replace(':', '');
  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;

View on GitHub (pinned to 94993f7401)

Solutions

  1. Include the host: socks5://host:port
  2. For local proxies use 127.0.0.1 or localhost explicitly
  3. Check for an accidental leading slash or colon that erased the host
  4. Reconstruct the URL from known parts rather than editing in place

Example fix

# before
BROWSE_PROXY_URL=socks5://:1080  # throws — no host

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

Strategy: validation

Validate before calling

function hasProxyHost(s: string): boolean {
  try { return !!new URL(s).hostname; }
  catch { return false; }
}

if (!hasProxyHost(proxyUrl)) {
  throw new Error('Proxy URL must include a host: scheme://host:port');
}

Type guard

function urlHasHostname(s: string): boolean {
  try { return !!new URL(s).hostname; } catch { return false; }
}

Try / catch

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

Prevention

When it happens

Trigger: Passing a proxy URL with no host component — only a port, only credentials, or only a path. `new URL('socks5://:1080')` succeeds but url.hostname is the empty string.

Common situations: Typo dropping the host; using a path-style URL; URL with only credentials and a port; copy-paste truncation that cut off the host.

Related errors


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