{"record":{"id":"88b4c4a91df130cc","repo":"MagicMirrorOrg/MagicMirror","slug":"failed-to-parse-client-ip-clientip","errorCode":null,"errorMessage":"Failed to parse client IP: ${clientIp}","messagePattern":"Failed to parse client IP: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"js/ip_access_control.js","lineNumber":31,"sourceCode":"\n\t\treturn whitelist.some((entry) => {\n\t\t\ttry {\n\t\t\t\t// CIDR notation\n\t\t\t\tif (entry.includes(\"/\")) {\n\t\t\t\t\tconst [rangeAddr, prefixLen] = ipaddr.parseCIDR(entry);\n\t\t\t\t\treturn addr.match(rangeAddr, prefixLen);\n\t\t\t\t}\n\n\t\t\t\t// Single IP address - let ipaddr.process normalize both\n\t\t\t\tconst allowedAddr = ipaddr.process(entry);\n\t\t\t\treturn addr.toString() === allowedAddr.toString();\n\t\t\t} catch {\n\t\t\t\tLog.warn(`Invalid whitelist entry: ${entry}`);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t} catch {\n\t\tLog.warn(`Failed to parse client IP: ${clientIp}`);\n\t\treturn false;\n\t}\n}\n\n/**\n * Resolves a client IP for both Express and Socket.IO requests.\n * If the direct peer is loopback, trust the first X-Forwarded-For value (local reverse proxy case).\n * Otherwise ignore X-Forwarded-For to prevent spoofing.\n * @param {object} req - Incoming request object (Express request or Socket.IO handshake request)\n * @returns {string} The resolved client IP address\n */\nfunction resolveClientIp (req) {\n\tconst directIp = req.socket?.remoteAddress || req.connection?.remoteAddress || req.ip;\n\tconst LOOPBACK_WHITELIST = [\"127.0.0.1\", \"::ffff:127.0.0.1\", \"::1\"];\n\n\tif (isAllowed(directIp, LOOPBACK_WHITELIST)) {\n\t\tconst forwardedFor = req.headers?.[\"x-forwarded-for\"];\n\t\tif (typeof forwardedFor === \"string\" && forwardedFor.trim().length > 0) {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/MagicMirrorOrg/MagicMirror/blob/4b4a59534f7da01e4030e46029fe9dd649a7675e/js/ip_access_control.js#L13-L49","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect what resolveClientIp returns — log or debug the raw headers (X-Forwarded-For, X-Real-IP) and fix the proxy sending them.","Sanitize/strip the forwarded header chain so only valid IPs remain, or trust only known proxy IPs.","If the source is a local/test client, ensure the test passes a real IP string like '127.0.0.1'.","Adjust the resolution logic in ip_access_control.js to try req.socket.remoteAddress before forwarded headers."],"exampleFix":"// before (proxy)\nproxy_set_header X-Forwarded-For \"$http_x_forwarded_for, unknown\";\n// after\nproxy_set_header X-Forwarded-For $remote_addr;","handlingStrategy":"type-guard","validationCode":"const ipaddr = require(\"ipaddr.js\");\nfunction safeResolveClientIp(req) {\n  const fwd = req.headers[\"x-forwarded-for\"];\n  const candidates = [fwd?.split(\",\")[0]?.trim(), req.socket?.remoteAddress].filter(Boolean);\n  return candidates.find(c => { try { ipaddr.process(c); return true; } catch { return false; } }) ?? null;\n}","typeGuard":"function isValidClientIp(ip) {\n  if (typeof ip !== \"string\" || ip.length === 0) return false;\n  try { ipaddr.process(ip); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  isAllowed(clientIp, whitelist);\n} catch {\n  Log.warn(`Failed to parse client IP: ${clientIp}; denying request`);\n  return false;\n}","preventionTips":["Configure your reverse proxy to send a clean X-Forwarded-For with $remote_addr.","Strip or ignore garbage segments in the forwarded chain before parsing.","Log raw headers once when debugging access issues to see what the parser receives."],"tags":["ip","parsing","proxy","security"],"backgroundTag":"invalid-client-ip","analyzedSha":"4b4a59534f7da01e4030e46029fe9dd649a7675e","analyzedAt":"2026-08-31T21:49:42.591Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}