{"record":{"id":"e150d504d34daff9","repo":"Hmbown/CodeWhale","slug":"base-url-must-use-http-or-https","errorCode":null,"errorMessage":"--base-url must use http or https","messagePattern":"--base-url must use http or https","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/scripts/compare-deployed-facts.mjs","lineNumber":108,"sourceCode":"  ];\n  for (const [field, expectedValue, deployedValue] of checks) {\n    if (expectedValue !== deployedValue) {\n      differences.push({ field, expected: expectedValue, deployed: deployedValue });\n    }\n  }\n  return differences;\n}\n\nasync function main() {\n  const args = parseArgs(process.argv.slice(2));\n  let baseUrl;\n  try {\n    baseUrl = new URL(args.baseUrl);\n  } catch {\n    throw new Error(`invalid --base-url: ${args.baseUrl}`);\n  }\n  if (!/^https?:$/.test(baseUrl.protocol)) {\n    throw new Error(\"--base-url must use http or https\");\n  }\n\n  const expectedRevision = args.expectedRevision || localRevision();\n  if (!expectedRevision || !/^[0-9a-f]{40}$/i.test(expectedRevision)) {\n    throw new Error(\"expected revision must be an exact 40-character Git SHA\");\n  }\n  if (!Number.isInteger(args.attempts) || args.attempts < 1 || args.attempts > 20) {\n    throw new Error(\"--attempts must be an integer from 1 to 20\");\n  }\n  if (!Number.isFinite(args.retryDelayMs) || args.retryDelayMs < 0 || args.retryDelayMs > 30_000) {\n    throw new Error(\"--retry-delay-ms must be between 0 and 30000\");\n  }\n\n  const facts = buildFacts();\n  const expected = {\n    sourceRevision: expectedRevision,\n    version: facts.version,\n    providerCount: facts.providers.length,","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/web/scripts/compare-deployed-facts.mjs#L90-L126","documentation":"compare-deployed-facts.mjs validates its --base-url CLI option before fetching. It parses the value with `new URL()` and then requires the parsed protocol to be exactly http: or https:. Any other scheme (ftp:, file:, ws:, etc.) throws this error so the script never issues requests to an unexpected protocol.","triggerScenarios":"Running `node web/scripts/compare-deployed-facts.mjs --base-url ftp://example.com` (or file:, //missing-scheme, etc.). The URL parses successfully but `baseUrl.protocol` is not 'http:' or 'https:'.","commonSituations":"Pasting a deploy URL that omits the scheme, using an internal custom scheme, or copying a URL from a tool that emits protocol-relative or non-http URLs.","solutions":["Pass a URL that starts with http:// or https://","Check for typos like htp:// or a missing scheme and fix the scheme part","If targeting a non-http service, proxy it through an https endpoint instead"],"exampleFix":"// before\nnode web/scripts/compare-deployed-facts.mjs --base-url example.com\n// after\nnode web/scripts/compare-deployed-facts.mjs --base-url https://example.com","handlingStrategy":"validation","validationCode":"function isValidBaseUrl(u) { try { return /^https?:$/.test(new URL(u).protocol); } catch { return false; } }\nif (!isValidBaseUrl(args.baseUrl)) throw new Error('bad --base-url');","typeGuard":"const isHttpUrl = (v) => { try { return /^https?:$/.test(new URL(v).protocol); } catch { return false; } };","tryCatchPattern":"try { run(args); } catch (e) { if (e.message.includes('--base-url')) { console.error('Use an http:// or https:// URL'); process.exitCode = 2; } else throw e; }","preventionTips":["Always include the scheme when writing deploy URLs","Normalize pasted URLs before passing them to scripts","Keep a canonical --base-url in CI config rather than retyping it"],"tags":["cli","url","validation"],"backgroundTag":"invalid-url-format","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}