denoland/deno · error · NodeTypeError

ERR_INVALID_URL

ERR_INVALID_URL

Error message

Invalid URL: ${urlStr}

What it means

When ClientRequest receives a string as its first argument, the polyfill parses it with new URL(urlStr). Deno's Web URL throws a generic TypeError on bad input, so the polyfill wraps it to attach Node's ERR_INVALID_URL code and the 'Invalid URL: <input>' message. It fires only for the string-input form; URL objects and options objects go through other branches.

Source

Thrown at ext/node/polyfills/_http_client.js:464

function isURL(input) {
  return ObjectPrototypeIsPrototypeOf(URL.prototype, input);
}

function ClientRequest(input, options, cb) {
  FunctionPrototypeCall(OutgoingMessage, this);

  if (typeof input === "string") {
    const urlStr = input;
    // Match Node: `new URL(...)` in ClientRequest surfaces as
    // ERR_INVALID_URL (node's internal URL constructor calls
    // bindingUrl.parse with raiseException=true). Deno's Web URL
    // throws a generic TypeError, so wrap it to attach the code.
    let parsed;
    try {
      parsed = new URL(urlStr);
    } catch {
      throw new ERR_INVALID_URL(urlStr);
    }
    input = urlToHttpOptions(parsed);
  } else if (isURL(input)) {
    input = urlToHttpOptions(input);
  } else {
    cb = options;
    options = input;
    input = null;
  }

  if (typeof options === "function") {
    cb = options;
    options = input || kEmptyObject;
  } else {
    options = ObjectAssign(input || {}, options);
  }

  let agent = options.agent;

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Include the scheme: 'http://' + host + path, or better, construct with new URL(path, base) first
  2. Validate before calling: if (!URL.canParse(urlStr)) fail with your own message
  3. Log the offending string when catching to find where the malformed value originates

Example fix

// before
const req = http.request(`${cfg.host}/api`); // cfg.host = 'api.example.com'

// after
const target = new URL('/api', `http://${cfg.host}`);
const req = http.request(target);
Defensive patterns

Strategy: validation

Validate before calling

// Node >= 18.17 / Deno
if (!URL.canParse(urlStr)) {
  throw new Error(`invalid target URL: ${JSON.stringify(urlStr)}`);
}
http.request(urlStr);

Type guard

function isParseableUrl(v) {
  if (typeof v !== 'string' || !v) return false;
  try { new URL(v); return true; } catch { return false; }
}

Try / catch

try { http.get(urlStr, cb); } catch (e) { if (e.code === 'ERR_INVALID_URL') { /* log e.input, reject user input */ } else throw e; }

Prevention

When it happens

Trigger: http.get('not-a-url'); http.request('example.com/path') (missing protocol); malformed bracket syntax like 'http://[::1:80/x'; strings built by concatenation that drop the scheme or contain spaces.

Common situations: Forgetting the http:// prefix when the value comes from an env var or config that stores a bare host; user-supplied URLs pasted into a CLI; template literals that interpolate undefined into the URL string.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/9cca0b286898ab5d. Report an issue: GitHub.