MagicMirrorOrg/MagicMirror · warning

Failed to parse client IP: ${clientIp}

Error message

Failed to parse client IP: ${clientIp}

What it means

isAllowed first parses the incoming client IP with ipaddr.process. If the client IP string cannot be parsed (the whole function is wrapped in try/catch), this warning is logged and access is denied, returning false. It guards against malformed or unusual address representations coming from the request layer.

Source

Thrown at js/ip_access_control.js:31

		return whitelist.some((entry) => {
			try {
				// CIDR notation
				if (entry.includes("/")) {
					const [rangeAddr, prefixLen] = ipaddr.parseCIDR(entry);
					return addr.match(rangeAddr, prefixLen);
				}

				// Single IP address - let ipaddr.process normalize both
				const allowedAddr = ipaddr.process(entry);
				return addr.toString() === allowedAddr.toString();
			} catch {
				Log.warn(`Invalid whitelist entry: ${entry}`);
				return false;
			}
		});
	} catch {
		Log.warn(`Failed to parse client IP: ${clientIp}`);
		return false;
	}
}

/**
 * Resolves a client IP for both Express and Socket.IO requests.
 * If the direct peer is loopback, trust the first X-Forwarded-For value (local reverse proxy case).
 * Otherwise ignore X-Forwarded-For to prevent spoofing.
 * @param {object} req - Incoming request object (Express request or Socket.IO handshake request)
 * @returns {string} The resolved client IP address
 */
function resolveClientIp (req) {
	const directIp = req.socket?.remoteAddress || req.connection?.remoteAddress || req.ip;
	const LOOPBACK_WHITELIST = ["127.0.0.1", "::ffff:127.0.0.1", "::1"];

	if (isAllowed(directIp, LOOPBACK_WHITELIST)) {
		const forwardedFor = req.headers?.["x-forwarded-for"];
		if (typeof forwardedFor === "string" && forwardedFor.trim().length > 0) {

View on GitHub (pinned to 4b4a59534f)

Solutions

  1. Inspect what resolveClientIp returns — log or debug the raw headers (X-Forwarded-For, X-Real-IP) and fix the proxy sending them.
  2. Sanitize/strip the forwarded header chain so only valid IPs remain, or trust only known proxy IPs.
  3. If the source is a local/test client, ensure the test passes a real IP string like '127.0.0.1'.
  4. Adjust the resolution logic in ip_access_control.js to try req.socket.remoteAddress before forwarded headers.

Example fix

// before (proxy)
proxy_set_header X-Forwarded-For "$http_x_forwarded_for, unknown";
// after
proxy_set_header X-Forwarded-For $remote_addr;
Defensive patterns

Strategy: type-guard

Validate before calling

const ipaddr = require("ipaddr.js");
function safeResolveClientIp(req) {
  const fwd = req.headers["x-forwarded-for"];
  const candidates = [fwd?.split(",")[0]?.trim(), req.socket?.remoteAddress].filter(Boolean);
  return candidates.find(c => { try { ipaddr.process(c); return true; } catch { return false; } }) ?? null;
}

Type guard

function isValidClientIp(ip) {
  if (typeof ip !== "string" || ip.length === 0) return false;
  try { ipaddr.process(ip); return true; } catch { return false; }
}

Try / catch

try {
  isAllowed(clientIp, whitelist);
} catch {
  Log.warn(`Failed to parse client IP: ${clientIp}; denying request`);
  return false;
}

Prevention

When it happens

Trigger: resolveClientIp produces a client IP string that ipaddr.process cannot parse — e.g. corrupted X-Forwarded-For headers containing garbage, unexpected unix-socket peer addresses, or '::ffff:' forms combined with invalid data.

Common situations: Reverse proxies injecting malformed X-Forwarded-For values; requests over abstract sockets or unusual transports in tests; spoofed headers from hostile clients; IPv6-mapped edge cases not handled by the caller.

Understand the failure class

Related errors


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