{"record":{"id":"3a534a15b39dc8b2","repo":"abhigyanpatwari/GitNexus","slug":"invalid-backend-url-must-be-a-well-formed-http","errorCode":null,"errorMessage":"Invalid backend URL: must be a well-formed http:// or https:// URL","messagePattern":"Invalid backend URL: must be a well-formed http:// or https:// URL","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"gitnexus-web/src/services/backend-client.ts","lineNumber":300,"sourceCode":"// ── Configuration ──────────────────────────────────────────────────────────\n\nlet _backendUrl = 'http://localhost:4747';\n\n/**\n * Validate that a backend URL is a safe http:// or https:// origin before\n * storing it as the fetch target base (CodeQL js/client-side-request-forgery).\n *\n * Throws if the URL uses a non-HTTP scheme (e.g. javascript:, data:, file://).\n * All other well-formed http/https URLs are accepted — the client intentionally\n * supports connecting to remote GitNexus servers, not just localhost.\n */\nexport function validateBackendUrl(url: string): void {\n  let parsed: URL;\n  try {\n    parsed = new URL(url);\n  } catch {\n    // Do not echo raw input — it may contain credentials.\n    throw new Error('Invalid backend URL: must be a well-formed http:// or https:// URL');\n  }\n  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n    // Use parsed.protocol only (scheme), not the full URL, to avoid leaking credentials.\n    throw new Error(`Backend URL must use http:// or https:// (got ${parsed.protocol})`);\n  }\n}\n\nexport const setBackendUrl = (url: string): void => {\n  const trimmed = url.replace(/\\/$/, '');\n  validateBackendUrl(trimmed);\n  _backendUrl = trimmed;\n};\n\nexport const getBackendUrl = (): string => _backendUrl;\n\n/**\n * Normalize a user-entered server URL into a base URL suitable for setBackendUrl().\n * Adds protocol if missing, strips trailing slashes, and strips a trailing /api suffix","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/gitnexus-web/src/services/backend-client.ts#L282-L318","documentation":"Thrown by validateBackendUrl() when `new URL(url)` throws — i.e. the input is not a parseable absolute URL (missing protocol, malformed host, stray characters). The raw input is deliberately NOT echoed in the message because it may contain embedded credentials (user:pass@host), which would leak into logs/error surfaces. This is the first of two URL checks; the second (error 11) covers the wrong-protocol case.","triggerScenarios":"Calling setBackendUrl(url) or validateBackendUrl(url) with a value like 'localhost:4747' (no protocol), 'my server', ':4747', an empty string, or any string the URL constructor rejects. Note normalizeServerUrl() exists to prepend a protocol and should be called first for user input.","commonSituations":"User typed a bare host:port into the server URL field without a protocol; programmatic caller bypassed normalizeServerUrl(); a copy-paste that dropped the scheme; trailing/leading whitespace breaking the URL parser.","solutions":["Run user input through normalizeServerUrl() first — it prepends http:// for localhost/127.0.0.1 and https:// otherwise","Provide a full URL including protocol: 'http://localhost:4747' or 'https://my-server.example.com'","Trim whitespace before validating","If the URL contains credentials, note the error won't echo them — supply a clean origin instead"],"exampleFix":"// before — bare host:port, URL constructor throws\nsetBackendUrl('localhost:4747'); // throws 'Invalid backend URL...'\n\n// after — normalize first, then set\nsetBackendUrl(normalizeServerUrl('localhost:4747')); // -> 'http://localhost:4747'","handlingStrategy":"validation","validationCode":"import { normalizeServerUrl } from './services/backend-client.js';\n// normalizeServerUrl prepends a protocol (http for localhost, https otherwise)\n// and strips trailing slashes + /api suffix BEFORE setBackendUrl validates\nconst safe = normalizeServerUrl(userInput);\nsetBackendUrl(safe); // won't throw 'Invalid backend URL'","typeGuard":"function isWellFormedUrl(s: string): boolean {\n  try { new URL(s); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  setBackendUrl(input);\n} catch (e) {\n  if (e instanceof Error && /Invalid backend URL/.test(e.message)) {\n    // input didn't parse — try normalizing, or prompt the user\n    const normalized = normalizeServerUrl(input);\n    setBackendUrl(normalized);\n  }\n  throw e;\n}","preventionTips":["Always run user input through normalizeServerUrl() before setBackendUrl()","Trim whitespace before validating","Note the error deliberately doesn't echo the input (may contain credentials) — log only the failure, not the value","Require a protocol in the input field (UI hint: 'http:// or https://')"],"tags":["validation","url","config","security"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}