{"record":{"id":"ba43fb9c1144c8af","repo":"garrytan/gstack","slug":"invalid-proxy-url-bad-port","errorCode":null,"errorMessage":"invalid proxy URL — bad port","messagePattern":"invalid proxy URL — bad port","errorType":"validation","errorClass":"ProxyConfigError","httpStatus":null,"severity":"error","filePath":"browse/src/proxy-config.ts","lineNumber":74,"sourceCode":"  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;\n  const envHasPass = !!opts.envPass;\n  const urlHasCreds = urlHasUser || urlHasPass;\n  const envHasCreds = envHasUser || envHasPass;\n\n  // D9 (codex correction): refuse on mixed sources. Silent override is a\n  // debugging trap — when a stale BROWSE_PROXY_USER from a prior session\n  // wins over a fresh --proxy URL, the user can't tell why.\n  if (urlHasCreds && envHasCreds) {\n    throw new ProxyConfigError(\n      'unset BROWSE_PROXY_USER/PASS or remove user:pass@ from --proxy',","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/proxy-config.ts#L56-L92","documentation":"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.","triggerScenarios":"Passing a proxy URL with port 0, a negative port, a port above 65535, or a non-numeric string in the port position.","commonSituations":"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.","solutions":["Use a port in 1..65535 (common defaults: 1080 for socks5, 8080/3128 for http)","Omit the port entirely to use the scheme default (80/443/1080)","Double-check the proxy server's actual listening port with its operator or `ss -tlnp`","Validate: `node -e \"const p=+process.argv[1]; console.log(Number.isInteger(p)&&p>0&&p<=65535)\" <port>`"],"exampleFix":"# before\nBROWSE_PROXY_URL=socks5://host:99999  # throws\n\n# after\nBROWSE_PROXY_URL=socks5://host:1080","handlingStrategy":"validation","validationCode":"function isValidPort(s: string): boolean {\n  try {\n    const u = new URL(s);\n    const port = u.port ? parseInt(u.port, 10)\n      : (u.protocol === 'http:' ? 80 : u.protocol === 'https:' ? 443 : 1080);\n    return Number.isInteger(port) && port > 0 && port <= 65535;\n  } catch { return false; }\n}\n\nif (!isValidPort(proxyUrl)) {\n  throw new Error('Proxy port must be an integer in 1..65535');\n}","typeGuard":"function isIntegerPort(p: number): boolean {\n  return Number.isInteger(p) && p > 0 && p <= 65535;\n}","tryCatchPattern":"try {\n  parseProxyConfig(opts);\n} catch (e) {\n  if (e instanceof ProxyConfigError && /bad port/.test(e.message)) {\n    console.error(`${e.message}. ${e.hint}`);\n  }\n  throw e;\n}","preventionTips":["Stick to well-known ports (1080 for SOCKS5, 8080/3128 for HTTP)","Omit the port to use the scheme default","Confirm the proxy's listening port with `ss -tlnp` or its operator","Validate the port as an integer in range in your config loader"],"tags":["proxy","config","invalid-port","network","proxy-config-error"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}