paperclipai/paperclip · error · Error

Invalid hostname: ${raw}

Error message

Invalid hostname: ${raw}

What it means

Thrown by normalizeHostnameInput in the catch block when the URL constructor throws (input is non-empty but not parseable as a URL even with an http:// prefix prepended). The original raw input is included verbatim in the message for diagnosis. This is the catch-all for malformed hostname strings that never get far enough to extract a hostname.

Source

Thrown at cli/src/config/hostnames.ts:13

export function normalizeHostnameInput(raw: string): string {
  const input = raw.trim();
  if (!input) {
    throw new Error("Hostname is required");
  }

  try {
    const url = input.includes("://") ? new URL(input) : new URL(`http://${input}`);
    const hostname = url.hostname.trim().toLowerCase();
    if (!hostname) throw new Error("Hostname is required");
    return hostname;
  } catch {
    throw new Error(`Invalid hostname: ${raw}`);
  }
}

export function parseHostnameCsv(raw: string): string[] {
  if (!raw.trim()) return [];
  const unique = new Set<string>();
  for (const part of raw.split(",")) {
    const hostname = normalizeHostnameInput(part);
    unique.add(hostname);
  }
  return Array.from(unique);
}

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Pass a bare domain or IP, optionally with http/https scheme and port: 'example.com', 'http://example.com:8080'.
  2. Strip paths, queries, and quotes before normalizing.
  3. If you need to accept URLs and extract the host, pre-validate with new URL() in a try/catch and pass only .hostname.

Example fix

// before
const h = normalizeHostnameInput('https://example.com/path?x=1 bad');
// after
const h = normalizeHostnameInput('example.com');
Defensive patterns

Strategy: validation

Validate before calling

function prevalidateHostname(raw: string): void {
  const trimmed = raw.trim();
  if (!trimmed) throw new Error("Hostname is required");
  // strip nothing; just try the same URL parse the normalizer will do
  try {
    const url = new URL(trimmed.includes("://") ? trimmed : `http://${trimmed}`);
    if (!url.hostname) throw new Error(`Invalid hostname: ${raw}`);
  } catch {
    throw new Error(`Invalid hostname: ${raw}`);
  }
}

Type guard

function isValidHostname(raw: string): boolean {
  const trimmed = raw.trim();
  if (!trimmed) return false;
  try {
    const url = new URL(trimmed.includes("://") ? trimmed : `http://${trimmed}`);
    return url.hostname.trim().length > 0;
  } catch {
    return false;
  }
}

Prevention

When it happens

Trigger: Calling normalizeHostnameInput with a string containing characters or structure that new URL() rejects, such as a hostname with spaces, control characters, unmatched brackets, or invalid %-encoding. Because the function prepends 'http://' when there is no scheme, inputs that already include a bad scheme also land here.

Common situations: A developer copies a hostname with a trailing path/query and bad characters, includes spaces, or pastes a value with stray quotes. Or mixes schemes like 'ftp://example.com' which is parseable but, combined with other bad input, throws.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/de2072c97c97fec0. Report an issue: GitHub.