{"record":{"id":"6e59dd44074088c5","repo":"lissy93/web-check","slug":"invalid-url-input","errorCode":null,"errorMessage":"Invalid URL: ${input}","messagePattern":"Invalid URL: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/_common/parse-target.js","lineNumber":19,"sourceCode":"// Wrap bare IPv6 in brackets for URL parsing (2+ colons = IPv6)\nexport const bracketIPv6 = (str) => {\n  const bare = str.replace(/^https?:\\/\\//i, '');\n  const host = bare.split('/')[0];\n  if (!host.startsWith('[') && (host.match(/:/g) || []).length >= 2)\n    return str.replace(host, `[${host}]`);\n  return str;\n};\n\n// Normalise a user-supplied target, stripping :port for DNS lookups\nexport const parseTarget = (input) => {\n  if (!input) throw new Error('No target provided');\n  let normalised = /^https?:\\/\\//i.test(input) ? input : `https://${input}`;\n  normalised = bracketIPv6(normalised);\n  let u;\n  try {\n    u = new URL(normalised);\n  } catch {\n    throw new Error(`Invalid URL: ${input}`);\n  }\n  return {\n    hostname: u.hostname.replace(/^\\[|]$/g, ''),\n    port: u.port || null,\n    protocol: u.protocol,\n    pathname: u.pathname || '/',\n    href: u.href,\n  };\n};\n\nexport default parseTarget;\n","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/lissy93/web-check/blob/af1a97759fc8bcc43c876c94f2ccb018ce215f90/api/_common/parse-target.js#L1-L31","documentation":"parseTarget prepends 'https://' to scheme-less inputs, brackets IPv6 literals, and hands the result to the URL constructor. If the constructor still rejects the string (unparseable hostname, malformed port, illegal characters), this error is thrown with the original input interpolated. It signals the target cannot be represented as a valid URL.","triggerScenarios":"Inputs like 'https://:', 'http://[::1', 'exa mple.com', 'example.com:notaport', or strings with control characters that survive normalisation.","commonSituations":"Typos in user-supplied hostnames, copy-pasted URLs with smart quotes or trailing punctuation, IPv6 addresses missing brackets (handled) but internally malformed (not handled), or empty-string hosts after scheme stripping.","solutions":["Inspect the exact input in the message and correct the malformed component","Validate/normalise the target in your own code before calling parseTarget (trim whitespace, strip punctuation)","URL-encode or reject user input containing spaces, brackets, or non-ASCII characters early"],"exampleFix":"// before\nparseTarget('exa mple.com:8080'); // throws Invalid URL\n\n// after\nconst clean = raw.trim().replace(/[\\s',]+$/g, '');\nparseTarget(clean);","handlingStrategy":"type-guard","validationCode":"const isValidTarget = (s) => {\n  try { new URL(/^https?:\\/\\//i.test(s) ? s : `https://${s}`); return true; }\n  catch { return false; }\n};\nif (!isValidTarget(input)) return badRequest(`unparseable target: ${input}`);","typeGuard":"const looksLikeHost = (s) =>\n  typeof s === 'string' &&\n  /^[a-z0-9.-]+(:\\d{2,5})?$/i.test(s.trim()) && !/[\\s<>\"]/g.test(s);","tryCatchPattern":"try { const t = parseTarget(input); }\ncatch (e) {\n  if (e.message.startsWith('Invalid URL:')) return badRequest('target must be a valid hostname or URL');\n  throw e;\n}","preventionTips":["Trim and strip trailing punctuation from user input before parsing","Reject inputs containing whitespace or unmatched brackets early","Mirror parseTarget's normalisation (scheme-prepend, IPv6 bracket) in client-side validation"],"tags":["validation","url-parsing","user-input"],"backgroundTag":"invalid-url-format","analyzedSha":"af1a97759fc8bcc43c876c94f2ccb018ce215f90","analyzedAt":"2026-08-27T11:44:27.410Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}