{"record":{"id":"bbb0303ead10ceb5","repo":"garrytan/gstack","slug":"invalid-proxy-url-missing-host","errorCode":null,"errorMessage":"invalid proxy URL — missing host","messagePattern":"invalid proxy URL — missing host","errorType":"validation","errorClass":"ProxyConfigError","httpStatus":null,"severity":"error","filePath":"browse/src/proxy-config.ts","lineNumber":64,"sourceCode":"  try {\n    url = new URL(opts.proxyUrl);\n  } catch {\n    throw new ProxyConfigError(\n      'expected scheme://[user:pass@]host:port',\n      `invalid proxy URL — could not parse`,\n    );\n  }\n\n  const scheme = url.protocol.replace(':', '');\n  if (scheme !== 'socks5' && scheme !== 'http' && scheme !== 'https') {\n    throw new ProxyConfigError(\n      'use socks5://, http://, or https://',\n      `unsupported proxy scheme '${scheme}'`,\n    );\n  }\n\n  if (!url.hostname) {\n    throw new ProxyConfigError(\n      'expected scheme://[user:pass@]host:port',\n      `invalid proxy URL — missing host`,\n    );\n  }\n\n  const port = url.port\n    ? parseInt(url.port, 10)\n    : (scheme === 'http' ? 80 : scheme === 'https' ? 443 : 1080);\n  if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n    throw new ProxyConfigError(\n      'expected scheme://[user:pass@]host:port',\n      `invalid proxy URL — bad port`,\n    );\n  }\n\n  const urlHasUser = !!url.username;\n  const urlHasPass = !!url.password;\n  const envHasUser = !!opts.envUser;","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/proxy-config.ts#L46-L82","documentation":"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.","triggerScenarios":"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.","commonSituations":"Typo dropping the host; using a path-style URL; URL with only credentials and a port; copy-paste truncation that cut off the host.","solutions":["Include the host: socks5://host:port","For local proxies use 127.0.0.1 or localhost explicitly","Check for an accidental leading slash or colon that erased the host","Reconstruct the URL from known parts rather than editing in place"],"exampleFix":"# before\nBROWSE_PROXY_URL=socks5://:1080  # throws — no host\n\n# after\nBROWSE_PROXY_URL=socks5://127.0.0.1:1080","handlingStrategy":"validation","validationCode":"function hasProxyHost(s: string): boolean {\n  try { return !!new URL(s).hostname; }\n  catch { return false; }\n}\n\nif (!hasProxyHost(proxyUrl)) {\n  throw new Error('Proxy URL must include a host: scheme://host:port');\n}","typeGuard":"function urlHasHostname(s: string): boolean {\n  try { return !!new URL(s).hostname; } catch { return false; }\n}","tryCatchPattern":"try {\n  parseProxyConfig(opts);\n} catch (e) {\n  if (e instanceof ProxyConfigError && /missing host/.test(e.message)) {\n    console.error(`${e.message}. ${e.hint}`);\n  }\n  throw e;\n}","preventionTips":["Always include the host: socks5://127.0.0.1:1080, not socks5://:1080","Use 127.0.0.1 or localhost explicitly for local proxies","Construct URLs from validated parts rather than editing strings","Validate hostname presence in your config loader"],"tags":["proxy","config","missing-host","network","proxy-config-error"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}