denoland/deno · error · TypeError

ERR_INVALID_URL

ERR_INVALID_URL

Error message

Invalid URL: ${urlStr}

What it means

https.request(url, ...) accepts a plain string and parses it with the WHATWG URL constructor; strings the parser rejects (no scheme, invalid characters, unbalanced brackets) are surfaced as ERR_INVALID_URL, matching Node behavior. The error is strictly about URL syntax — passing a URL object skips string parsing entirely and cannot produce it.

Source

Thrown at ext/node/polyfills/https.ts:684

let globalAgent = new (Agent as any)({
  keepAlive: true,
  scheduling: "lifo",
  timeout: 5000,
});

/** Makes a request to an https server. */
function request(...args: any[]) {
  let options: any = {};

  if (typeof args[0] === "string") {
    const urlStr = ArrayPrototypeShift(args);
    // Match Node: surface invalid URL strings as ERR_INVALID_URL.
    let parsed;
    try {
      parsed = new URL(urlStr);
    } catch {
      throw new ERR_INVALID_URL(urlStr);
    }
    options = urlToHttpOptions(parsed);
  } else if (ObjectPrototypeIsPrototypeOf(URL.prototype, args[0])) {
    options = urlToHttpOptions(ArrayPrototypeShift(args));
  }

  if (args[0] && typeof args[0] !== "function") {
    ObjectAssign(options, ArrayPrototypeShift(args));
  }

  options._defaultAgent = globalAgent;
  ArrayPrototypeUnshift(args, options);

  return new ClientRequest(args[0], args[1], args[2]);
}

// `agent-base` (used by `@npmcli/agent`, `http-proxy-agent`, etc.) figures
// out whether a polymorphic agent should behave as https by scanning the

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Normalize before the call: prefix the scheme when missing, e.g. url.startsWith('http') ? url : 'https://' + url, and trim() the value.
  2. Validate with new URL(str) (or URL.canParse(str) where available) at config-load time and fail with your own message.
  3. Pass a URL object (new URL(...)) instead of a string to bypass string parsing.

Example fix

// before
const req = https.request(`${host}/v1/users`); // host lacked a scheme -> ERR_INVALID_URL

// after
const target = new URL(`https://${host.replace(/\/+$/, '')}/v1/users`);
const req = https.request(target);
Defensive patterns

Strategy: validation

Validate before calling

function parseRequestUrl(urlStr) {
  const trimmed = String(urlStr).trim();
  const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
  try {
    return new URL(withScheme);
  } catch {
    throw new Error(`Invalid request URL: ${JSON.stringify(urlStr)}`);
  }
}
https.request(parseRequestUrl(rawTarget));

Type guard

function isParsableUrl(s) {
  try { new URL(s); return true; } catch { return false; }
}

Prevention

When it happens

Trigger: https.request('example.com/data') (no scheme); URLs containing spaces or raw non-ASCII/control characters; 'https://[::1' (unclosed IPv6 bracket); values read from env vars with trailing whitespace or newline.

Common situations: Building URLs by concatenation that drops or mangles the scheme; passing user-supplied or config-file strings straight to https.request; typo'd schemes like 'htps://'.

Related errors


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