MagicMirrorOrg/MagicMirror · error

invalid url: ${req.url}

Error message

invalid url: ${req.url}

What it means

In the `/cors` proxy handler (js/server_functions.js:70), the URL is extracted with the regex `url=(.+?)$` applied to `req.url`. If the request path contains no `url=` parameter at all, no match is produced, and the handler returns HTTP 400 with the message `invalid url: <req.url>` after logging it via `Log.error`. Note the returned string is the literal template-interpolated request URL, not a fixed message.

Source

Thrown at js/server_functions.js:70

 * Only the url-param of the input request url is required. It must be the last parameter.
 * @param {Request} req - the request
 * @param {Response} res - the result
 * @returns {Promise<void>} A promise that resolves when the response is sent
 */
async function cors (req, res) {
	if (global.config.cors === "disabled") {
		Log.error("CORS is disabled, you need to enable it in `config.js` by setting `cors` to `allowAll` or `allowWhitelist`");
		return res.status(403).json({ error: "CORS proxy is disabled" });
	}
	let url;
	try {
		const urlRegEx = "url=(.+?)$";

		const match = new RegExp(urlRegEx, "g").exec(req.url);
		if (!match) {
			url = `invalid url: ${req.url}`;
			Log.error(url);
			return res.status(400).send(url);
		} else {
			url = match[1];
			if (typeof global.config !== "undefined") {
				if (config.hideConfigSecrets) {
					url = replaceSecretPlaceholder(url);
				}
			}

			// Validate protocol before attempting connection (non-http/https are never allowed)
			let parsed;
			try {
				parsed = new URL(url);
			} catch {
				Log.warn(`SSRF blocked (invalid URL): ${url}`);
				return res.status(403).json({ error: "Forbidden: private or reserved addresses are not allowed" });
			}
			if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
				Log.warn(`SSRF blocked (protocol): ${url}`);

View on GitHub (pinned to 4b4a59534f)

Solutions

  1. Include a properly encoded target in the query: request `/cors?url=` + encodeURIComponent(targetUrl).
  2. Check the server log line `invalid url: ...` to see exactly what path was received and fix the client-side URL construction accordingly.
  3. If the source URL is coming from module config, guard that the value is a non-empty string before building the proxy URL.
  4. Watch for double encoding: the proxy itself parses the raw `req.url`, so encode the target once, not twice.

Example fix

// before — missing/misspelled parameter
fetch('/cors?target=' + target)
// after
fetch('/cors?url=' + encodeURIComponent(target))
Defensive patterns

Strategy: validation

Validate before calling

function buildProxyUrl(baseUrl, target) {
  if (typeof target !== 'string' || target.trim() === '') {
    throw new TypeError('cors proxy target must be a non-empty string');
  }
  return `${baseUrl}/cors?url=${encodeURIComponent(target)}`;
}

Type guard

function isProxiableTarget(target) {
  return typeof target === 'string' && target.trim().length > 0 && /^https?:\/\//i.test(target.trim());
}

Try / catch

try {
  if (!isProxiableTarget(target)) throw new TypeError('missing or empty url parameter for /cors');
  const res = await fetch(`/cors?url=${encodeURIComponent(target)}`);
  if (res.status === 400) throw new Error(`/cors rejected request: ${await res.text()}`);
  return await res.text();
} catch (err) {
  console.error('cors proxy request failed', err);
}

Prevention

When it happens

Trigger: A request hits `/cors` (or `/cors?foo=bar`) without a `url=` query parameter; the URL parameter is misnamed (`?target=` or `?src=`); the query string is mangled so `url=` never appears in `req.url` (e.g. an HTTP client that strips the query, or a double-encoding/relative-URL mistake that yields `/cors` with no query at all); a trailing question mark or HTML form submit that drops the param.

Common situations: Hand-written fetch/curl calls to the proxy forgetting the `?url=` parameter; a module config where the target URL is empty/undefined so the template produces `/cors?url=undefined` is actually fine, but an empty-string interpolation or string-building bug drops the param entirely; clicking a bookmark to `/cors` directly.

Related errors


AI-assisted analysis of MagicMirrorOrg/MagicMirror@4b4a59534f (2026-08-31). Data as JSON: /api/errors/697316ec7b954d77. Report an issue: GitHub.