{"record":{"id":"2722d33eba7eace8","repo":"XTLS/Xray-core","slug":"log-mask-ipv4-mask-must-be-divisible-by-8-and-bet","errorCode":null,"errorMessage":"Log Mask: ipv4 mask must be divisible by 8 and between 0-32","messagePattern":"Log Mask: ipv4 mask must be divisible by 8 and between 0-32","errorType":"validation","errorClass":"errors.Error","httpStatus":null,"severity":"warning","filePath":"app/log/log.go","lineNumber":197,"sourceCode":"\t\t\tif len(parts) >= 1 && parts[0] != \"\" {\n\t\t\t\ti, err := strconv.Atoi(strings.TrimPrefix(parts[0], \"/\"))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 32, 128, err\n\t\t\t\t}\n\t\t\t\tm4 = i\n\t\t\t}\n\t\t\tif len(parts) >= 2 && parts[1] != \"\" {\n\t\t\t\ti, err := strconv.Atoi(strings.TrimPrefix(parts[1], \"/\"))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn 32, 128, err\n\t\t\t\t}\n\t\t\t\tm6 = i\n\t\t\t}\n\t\t}\n\t}\n\n\tif m4%8 != 0 || m4 > 32 || m4 < 0 {\n\t\treturn 32, 128, errors.New(\"Log Mask: ipv4 mask must be divisible by 8 and between 0-32\")\n\t}\n\n\treturn m4, m6, nil\n}\n\n// MaskedMsgWrapper is to wrap the string() method to mask IP addresses in the log.\ntype MaskedMsgWrapper struct {\n\tlog.Message\n\tMask4 int\n\tMask6 int\n}\n\nvar (\n\tipv4Regex = regexp.MustCompile(`(\\d{1,3}\\.){3}\\d{1,3}`)\n\tipv6Regex = regexp.MustCompile(`(?:[\\da-fA-F]{0,4}:[\\da-fA-F]{0,4}){2,7}`)\n)\n\nfunc (m *MaskedMsgWrapper) String() string {","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/app/log/log.go#L179-L215","documentation":"ParseMaskAddress validates the IPv4 mask parsed from the log mask address setting: after resolving named presets (half/quarter/full) or numeric 'm4+m6' forms, m4 must be in 0..32 and divisible by 8. Otherwise the default safe mask (32/128, i.e. fully masked) is returned together with this error.","triggerScenarios":"Setting log maskAddress to a numeric form whose IPv4 part fails validation: '33+128', '12', '-8', '9/24' style values — anything not a multiple of 8 within 0-32. Note only m4 is range-checked here; m6 is unconstrained by this specific error.","commonSituations":"Copy-pasting CIDR notation like '/24' with unexpected prefixes; assuming any 0-32 value works when only octet-aligned masks (0,8,16,24,32) are accepted; typos in the m4+m6 syntax.","solutions":["Use one of the named presets: 'half' (16/32), 'quarter' (8/16), or 'full' (0/0)","If numeric, ensure the IPv4 part is 0, 8, 16, 24, or 32, e.g. '24+56'","Re-check the value against the error constraints after any config template upgrade"],"exampleFix":"// before\n\"log\": { \"maskAddress\": \"20+64\" } // 20 not divisible by 8\n// after\n\"log\": { \"maskAddress\": \"24+64\" } // valid: 24 % 8 == 0, 24 <= 32","handlingStrategy":"validation","validationCode":"// Validate a mask address before applying config (mirror of ParseMaskAddress):\nfunc validMask(m4 int) bool { return m4 >= 0 && m4 <= 32 && m4%8 == 0 }\n// or simply call the real parser:\nif _, _, err := log.ParseMaskAddress(cfgValue); err != nil {\n    return fmt.Errorf(\"invalid maskAddress %q: %w\", cfgValue, err)\n}","typeGuard":"func isValidIPv4Mask(m4 int) bool {\n    return m4 >= 0 && m4 <= 32 && m4%8 == 0\n}","tryCatchPattern":null,"preventionTips":["Prefer named presets: full, half, quarter","If numeric, restrict m4 to 0/8/16/24/32","Note the failure mode is safe: masking falls back to 32/128 (fully masked)"],"tags":["logging","config","validation","privacy"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}