lissy93/web-check · error · Error

Invalid URL: ${input}

Error message

Invalid URL: ${input}

What it means

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.

Source

Thrown at api/_common/parse-target.js:19

// Wrap bare IPv6 in brackets for URL parsing (2+ colons = IPv6)
export const bracketIPv6 = (str) => {
  const bare = str.replace(/^https?:\/\//i, '');
  const host = bare.split('/')[0];
  if (!host.startsWith('[') && (host.match(/:/g) || []).length >= 2)
    return str.replace(host, `[${host}]`);
  return str;
};

// Normalise a user-supplied target, stripping :port for DNS lookups
export const parseTarget = (input) => {
  if (!input) throw new Error('No target provided');
  let normalised = /^https?:\/\//i.test(input) ? input : `https://${input}`;
  normalised = bracketIPv6(normalised);
  let u;
  try {
    u = new URL(normalised);
  } catch {
    throw new Error(`Invalid URL: ${input}`);
  }
  return {
    hostname: u.hostname.replace(/^\[|]$/g, ''),
    port: u.port || null,
    protocol: u.protocol,
    pathname: u.pathname || '/',
    href: u.href,
  };
};

export default parseTarget;

View on GitHub (pinned to af1a97759f)

Solutions

  1. Inspect the exact input in the message and correct the malformed component
  2. Validate/normalise the target in your own code before calling parseTarget (trim whitespace, strip punctuation)
  3. URL-encode or reject user input containing spaces, brackets, or non-ASCII characters early

Example fix

// before
parseTarget('exa mple.com:8080'); // throws Invalid URL

// after
const clean = raw.trim().replace(/[\s',]+$/g, '');
parseTarget(clean);
Defensive patterns

Strategy: type-guard

Validate before calling

const isValidTarget = (s) => {
  try { new URL(/^https?:\/\//i.test(s) ? s : `https://${s}`); return true; }
  catch { return false; }
};
if (!isValidTarget(input)) return badRequest(`unparseable target: ${input}`);

Type guard

const looksLikeHost = (s) =>
  typeof s === 'string' &&
  /^[a-z0-9.-]+(:\d{2,5})?$/i.test(s.trim()) && !/[\s<>"]/g.test(s);

Try / catch

try { const t = parseTarget(input); }
catch (e) {
  if (e.message.startsWith('Invalid URL:')) return badRequest('target must be a valid hostname or URL');
  throw e;
}

Prevention

When it happens

Trigger: Inputs like 'https://:', 'http://[::1', 'exa mple.com', 'example.com:notaport', or strings with control characters that survive normalisation.

Common situations: 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.

Related errors


AI-assisted analysis of lissy93/web-check@af1a97759f (2026-08-27). Data as JSON: /api/errors/6e59dd44074088c5. Report an issue: GitHub.