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
- Include a properly encoded target in the query: request `/cors?url=` + encodeURIComponent(targetUrl).
- Check the server log line `invalid url: ...` to see exactly what path was received and fix the client-side URL construction accordingly.
- If the source URL is coming from module config, guard that the value is a non-empty string before building the proxy URL.
- 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
- Always send the parameter named exactly `url=` and encode the target with encodeURIComponent
- Validate the target is a non-empty absolute http(s) URL before building the request
- Check module config for undefined/empty feed URLs that produce empty parameters
- Read the server log's `invalid url: <req.url>` to debug exactly what was received
- Unit-test URL construction helpers that build /cors requests
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
- CORS proxy is disabled
- Forbidden: private or reserved addresses are not allowed
- [compliments] Invalid URL: ${url}
- Failed to parse client IP: ${clientIp}
AI-assisted analysis of MagicMirrorOrg/MagicMirror@4b4a59534f (2026-08-31).
Data as JSON: /api/errors/697316ec7b954d77.
Report an issue: GitHub.