{"record":{"id":"1b5b152594f21e44","repo":"abhigyanpatwari/GitNexus","slug":"invalid-llm-base-url-must-be-a-well-formed-http","errorCode":null,"errorMessage":"Invalid LLM base URL: must be a well-formed http:// or https:// URL","messagePattern":"Invalid LLM base URL: must be a well-formed http:// or https:// URL","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/wiki/llm-client.ts","lineNumber":247,"sourceCode":" *  - file://, data:, javascript:, and any other non-HTTP scheme\n *  - http:// aimed at non-loopback hosts unless explicitly allowlisted\n *    (avoids SSRF against internal networks by default)\n *\n * Throws with a descriptive message on validation failure so callers surface a\n * clear error rather than an opaque network error.\n */\nexport function validateLLMBaseUrl(\n  baseUrl: string,\n  allowedInsecureHttpHosts: readonly string[] = parseLLMAllowedInsecureHttpHosts(\n    process.env[LLM_ALLOW_INSECURE_CONNECTION_ENV],\n  ),\n): void {\n  let parsed: URL;\n  try {\n    parsed = new URL(baseUrl);\n  } catch {\n    // Do not include the raw input in the message — it may contain credentials.\n    throw new Error('Invalid LLM base URL: must be a well-formed http:// or https:// URL');\n  }\n\n  if (!['https:', 'http:'].includes(parsed.protocol)) {\n    // Use parsed.protocol only (scheme), not the full URL, to avoid leaking credentials.\n    throw new Error(`LLM base URL must use http:// or https:// (got ${parsed.protocol})`);\n  }\n\n  if (parsed.protocol === 'http:') {\n    // Node's URL parser preserves IPv6 brackets in hostname (e.g. \"[::1]\"),\n    // so strip them before comparing to bare address literals.\n    const host = parsed.hostname.toLowerCase().replace(/^\\[|\\]$/g, '');\n    const allowedHosts = new Set(allowedInsecureHttpHosts.map(normalizeAllowedInsecureHttpHost));\n    if (host !== 'localhost' && host !== '127.0.0.1' && host !== '::1' && !allowedHosts.has(host)) {\n      // Use parsed.origin (scheme+host+port, no credentials) instead of the full URL.\n      throw new Error(\n        `Insecure http:// LLM base URLs are only allowed for localhost/127.0.0.1 ` +\n          `or hosts listed by --allow-insecure-connection / ${LLM_ALLOW_INSECURE_CONNECTION_ENV}. ` +\n          `Use https:// for remote endpoints (got ${parsed.origin})`,","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/52924ef12c2290ceee4612526a828ec4cdf2047f/gitnexus/src/core/wiki/llm-client.ts#L229-L265","documentation":"validateLLMBaseUrl parses the value supplied via `--base-url` (or provider config) with `new URL()` and throws when parsing fails, i.e. the string is not an absolute well-formed URL. The message deliberately omits the raw input because base URLs frequently embed API keys as credentials; only the failure class is reported. This is the first of three validation stages (parse, scheme, insecure-host).","triggerScenarios":"Passing a bare host or host:port (`--base-url api.example.com/v1`), a relative path (`/v1`), a string with spaces or unmatched brackets, or a fully empty value; programmatically passing a variable that is undefined-interpolated into the URL string.","commonSituations":"Users omitting the https:// scheme; copy-pasting from docs that strip the scheme; trailing whitespace/newline in the value from a shell variable or .env; wrong env var referenced so the value is literally 'undefined'.","solutions":["Supply an absolute URL with scheme: `--base-url https://api.example.com/v1`","Trim whitespace/newlines if the value comes from an env var or script variable","If the value intentionally contains credentials (user:pass@host), keep the scheme and move the key to `--api-key` instead"],"exampleFix":"# before\ngitnexus wiki --provider custom --base-url api.example.com/v1\n\n# after\ngitnexus wiki --provider custom --base-url https://api.example.com/v1","handlingStrategy":"validation","validationCode":"function isParsableAbsoluteUrl(value: string): boolean {\n  try { new URL(value); return true; } catch { return false; }\n}\nif (!isParsableAbsoluteUrl(baseUrl)) throw new Error('baseUrl must be an absolute http(s) URL');","typeGuard":"function isParsableAbsoluteUrl(value: string): boolean {\n  try { new URL(value); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  validateLLMBaseUrl(baseUrl);\n} catch (err) {\n  if (err instanceof Error && err.message.includes('well-formed http:// or https://')) {\n    // likely missing scheme — prepend https:// and re-validate once\n  }\n}","preventionTips":["Validate base URLs with `new URL()` at config-load time, not at request time","Normalize env-provided URLs (trim whitespace/newlines) before use","Fail fast in setup wizards: test the URL before persisting provider config"],"tags":["llm","url-validation","configuration","gitnexus"],"backgroundTag":"invalid-url","analyzedSha":"52924ef12c2290ceee4612526a828ec4cdf2047f","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}