denoland/deno · error · TypeError

Invalid URL: '${href}' with base '${maybeBase}'

Error message

Invalid URL: '${href}' with base '${maybeBase}'

What it means

Deno's URL implementation (ext/web/00_url.js:113) parses via a Rust op; a non-zero failure status surfaces as TypeError carrying the offending href and base. This matches WHATWG URL parser rejections: input with no valid scheme when no base is supplied, an invalid base, or malformed components such as spaces in the host or unsupported scheme characters.

Source

Thrown at ext/web/00_url.js:113

    href,
    maybeBase,
    componentsBuf,
  );
}

/**
 * @param {number} status
 * @param {string} href
 * @param {string} [maybeBase]
 * @returns {string}
 */
function getSerialization(status, href, maybeBase) {
  if (status === 0) {
    return href;
  } else if (status === 1) {
    return op_url_get_serialization();
  } else {
    throw new TypeError(
      `Invalid URL: '${href}'` +
        (maybeBase ? ` with base '${maybeBase}'` : ""),
    );
  }
}

class URLSearchParams {
  [_list];
  [_urlObject] = null;

  /**
   * @param {string | [string][] | Record<string, string>} init
   */
  constructor(init = undefined) {
    this[webidl.brand] = webidl.brand;
    // `undefined` is the default value of an optional argument, so it means
    // "not passed". `null` is a value, and per WebIDL union resolution it
    // reaches the USVString overload as "null".

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Wrap construction in try/catch and fall back to a sanitized default or a typed error of your own
  2. Validate before parsing: check scheme with a regex or require a base
  3. Encode user-controlled path/query pieces with encodeURIComponent before composing the URL string

Example fix

// before
const u = new URL(userInput);

// after
let u: URL;
try {
  u = new URL(userInput, 'https://example.com');
} catch {
  throw new Error(`invalid redirect target: ${userInput}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const URL_RE = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
if (!URL_RE.test(input) && !base) {
  throw new Error(`not a URL: ${input}`);
}

Type guard

function isParseableUrl(input: string, base?: string): boolean {
  try {
    new URL(input, base);
    return true;
  } catch {
    return false;
  }
}

Try / catch

let u: URL;
try {
  u = new URL(input, baseUrl);
} catch (e) {
  if (e instanceof TypeError) {
    throw new Error(`invalid URL from user input: ${JSON.stringify(input)}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: new URL('not a url'); new URL('/relative/path') with no base; new URL('/path', 'notaurl'); an input host containing a space like 'http://exa mple.com'; a base whose scheme cannot be used for relative resolution.

Common situations: Building URLs from user input (search boxes, CLI arguments, query params) without validation; forgetting the base when resolving scraped relative links; empty or partially-populated env-provided endpoints; unescaped Unicode or control characters in hostnames.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/1647cd80a397e755. Report an issue: GitHub.