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 theView on GitHub (pinned to 9ad36f7a2c)
Solutions
- Normalize before the call: prefix the scheme when missing, e.g. url.startsWith('http') ? url : 'https://' + url, and trim() the value.
- Validate with new URL(str) (or URL.canParse(str) where available) at config-load time and fail with your own message.
- 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
- Always construct request URLs from a URL object or a template starting with https://.
- Trim() values read from env vars and config files before using them as URLs.
- Validate URLs once at config-load time, not per request.
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
- ERR_HTTP2_UNSUPPORTED_PROTOCOL
- Request url protocol must be 'http:' or 'https:': received '
- invalid ${name}, must not be infinity or NaN
- ERR_INVALID_ARG_TYPE
- ERR_INVALID_URL
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/436ac5e98d462546.
Report an issue: GitHub.