{"record":{"id":"0c4b3a492edb7fbf","repo":"JuliusBrussee/caveman","slug":"invalid-listener","errorCode":null,"errorMessage":"invalid listener","messagePattern":"invalid listener","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":19030,"sourceCode":"// portListening probes a TCP port with a short timeout — used to detect whether\n// the proxy is already up, so start/wrap can say so without false positives.\nfunction portListening(host: string, port: number): Promise<boolean> {\n  return new Promise((resolve) => {\n    const sock = netConnect({ host, port });\n    const finish = (v: boolean) => { sock.destroy(); resolve(v); };\n    sock.setTimeout(600);\n    sock.once(\"connect\", () => finish(true));\n    sock.once(\"timeout\", () => finish(false));\n    sock.once(\"error\", () => finish(false));\n  });\n}\n\nfunction standaloneProxyEndpoint(): { host: string; port: number; listen: string } {\n  const listen = (process.env.CAVEMAN_LISTEN ?? PROXY_ADDR).trim();\n  try {\n    const url = new URL(`http://${listen}`);\n    const port = Number(url.port);\n    if (!url.hostname || !Number.isInteger(port) || port < 1 || port > 65535 || url.pathname !== \"/\") throw new Error(\"invalid listener\");\n    return { host: url.hostname, port, listen };\n  } catch {\n    throw new Error(`invalid CAVEMAN_LISTEN ${JSON.stringify(listen)}; expected host:port`);\n  }\n}\n\nexport function gatewayHostPort(gw = gatewayURL()): { host: string; port: number } {\n  try {\n    const u = new URL(gw);\n    const defaultPort = u.protocol === \"https:\" ? 443 : 80;\n    return { host: u.hostname || \"127.0.0.1\", port: Number(u.port) || defaultPort };\n  } catch {\n    return { host: \"127.0.0.1\", port: 8787 };\n  }\n}\n\nfunction isCliEntrypoint(): boolean {\n  if (!process.argv[1]) return false;","sourceCodeStart":19012,"sourceCodeEnd":19048,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L19012-L19048","documentation":"Internal sentinel thrown inside standaloneProxyEndpoint() when CAVEMAN_LISTEN (or the default PROXY_ADDR) does not parse as a valid host:port listener. The outer catch immediately converts it into the more descriptive 'invalid CAVEMAN_LISTEN ... expected host:port' error (index 555), so users normally never see this bare message. It validates hostname presence, integer port in 1-65535, and no path component.","triggerScenarios":"CAVEMAN_LISTEN value, once wrapped as `http://${listen}` and parsed with new URL(), yields: empty hostname, non-integer or out-of-range port (0, 99999), or a non-\"/\" pathname (e.g. 'host:port/extra' or missing port).","commonSituations":"Setting CAVEMAN_LISTEN=\":8080\" variants whose port parses oddly, \"localhost:0\", \"localhost:99999\", or \"localhost:8080/path\" when launching the standalone proxy.","solutions":["Set CAVEMAN_LISTEN to a plain host:port, e.g. CAVEMAN_LISTEN=127.0.0.1:8080.","Remove any path or scheme from the value (no 'localhost:8080/api', no 'http://...').","Use a port between 1 and 65535.","Unset CAVEMAN_LISTEN to fall back to the built-in default PROXY_ADDR."],"exampleFix":"// before\nCAVEMAN_LISTEN=localhost:99999 caveman proxy\n// after\nCAVEMAN_LISTEN=127.0.0.1:8080 caveman proxy","handlingStrategy":"validation","validationCode":"function isValidListen(v: string | undefined): boolean {\n  if (!v) return true; // falls back to default\n  try {\n    const u = new URL(`http://${v.trim()}`);\n    const p = Number(u.port);\n    return !!u.hostname && Number.isInteger(p) && p >= 1 && p <= 65535 && u.pathname === \"/\";\n  } catch { return false; }\n}\nif (!isValidListen(process.env.CAVEMAN_LISTEN)) throw new Error(\"CAVEMAN_LISTEN must be host:port\");","typeGuard":null,"tryCatchPattern":"try {\n  startStandaloneProxy();\n} catch (e) {\n  if (e instanceof Error && /invalid (listener|CAVEMAN_LISTEN)/.test(e.message)) {\n    console.error(\"Set CAVEMAN_LISTEN like 127.0.0.1:8080\");\n  } else throw e;\n}","preventionTips":["Always set CAVEMAN_LISTEN as plain host:port — no scheme, path, or extra whitespace","Keep ports within 1-65535","Echo the value (`echo \"$CAVEMAN_LISTEN\"`) in scripts to catch quoting mistakes","Omit the variable entirely to use the default listener"],"tags":["configuration","env","cli","url"],"backgroundTag":"invalid-env-var-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}