{"record":{"id":"7a8b92bf8a6861c1","repo":"slackhq/nebula","slug":"invalid-mask-s-for-cidr-s","errorCode":null,"errorMessage":"invalid mask: %s for cidr: %s","messagePattern":"invalid mask: (.+?) for cidr: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"calculated_remote.go","lineNumber":26,"sourceCode":"\t\"net/netip\"\n\t\"strconv\"\n\n\t\"github.com/gaissmai/bart\"\n\t\"github.com/slackhq/nebula/config\"\n)\n\n// This allows us to \"guess\" what the remote might be for a host while we wait\n// for the lighthouse response. See \"lighthouse.calculated_remotes\" in the\n// example config file.\ntype calculatedRemote struct {\n\tipNet netip.Prefix\n\tmask  netip.Prefix\n\tport  uint32\n}\n\nfunc newCalculatedRemote(cidr, maskCidr netip.Prefix, port int) (*calculatedRemote, error) {\n\tif maskCidr.Addr().BitLen() != cidr.Addr().BitLen() {\n\t\treturn nil, fmt.Errorf(\"invalid mask: %s for cidr: %s\", maskCidr, cidr)\n\t}\n\n\tmasked := maskCidr.Masked()\n\tif port < 0 || port > math.MaxUint16 {\n\t\treturn nil, fmt.Errorf(\"invalid port: %d\", port)\n\t}\n\n\treturn &calculatedRemote{\n\t\tipNet: maskCidr,\n\t\tmask:  masked,\n\t\tport:  uint32(port),\n\t}, nil\n}\n\nfunc (c *calculatedRemote) String() string {\n\treturn fmt.Sprintf(\"CalculatedRemote(mask=%v port=%d)\", c.ipNet, c.port)\n}\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/calculated_remote.go#L8-L44","documentation":"newCalculatedRemote builds a calculated_remote from a lighthouse CIDR and a mask CIDR; the mask must address the same IP family (same bit length) as the CIDR so masking can combine them. It throws this when the mask's address family (e.g. IPv4) differs from the CIDR's (e.g. IPv6), making the mask unusable for that CIDR.","triggerScenarios":"Calling newCalculatedRemote (via lighthouse.calculated_remotes config loading) where the `mask` prefix and the entry's CIDR key use different families — e.g. cidr=10.0.42.0/24 with mask=fd00::/8, or vice versa.","commonSituations":"Nebula calculated_remotes configs where a mask was copy-pasted from an IPv6 block onto an IPv4 CIDR (or the opposite), often when migrating an overlay network between address families.","solutions":["Make the mask prefix use the same IP family as the CIDR (e.g. mask=255.255.0.0/16 for an IPv4 CIDR)","Check the error text: the first prefix is the mask, the second is the CIDR; fix the one with the wrong family","Validate family equality before calling newCalculatedRemote by comparing maskCidr.Addr().BitLen() == cidr.Addr().BitLen()"],"exampleFix":"// before\nlighthouse:\n  calculated_remotes:\n    10.0.42.0/24:\n      - mask: fd00::/8\n        port: 4242\n// after\nlighthouse:\n  calculated_remotes:\n    10.0.42.0/24:\n      - mask: 10.0.0.0/8\n        port: 4242","handlingStrategy":"validation","validationCode":"func validFamily(cidr, mask netip.Prefix) bool {\n\treturn cidr.Addr().BitLen() == mask.Addr().BitLen()\n}\n// call before newCalculatedRemote; reject config entries where !validFamily","typeGuard":"func isMaskValidForCidr(mask, cidr netip.Prefix) bool {\n\treturn mask.IsValid() && cidr.IsValid() && mask.Addr().BitLen() == cidr.Addr().BitLen()\n}","tryCatchPattern":"cr, err := newCalculatedRemote(cidr, maskCidr, port)\nif err != nil {\n\tvar famErr bool\n\tif strings.HasPrefix(err.Error(), \"invalid mask:\") {\n\t\tfamErr = true // log config key and skip or fail reload\n\t}\n\treturn fmt.Errorf(\"calculated_remotes %s: %w\", cidr, err)\n}","preventionTips":["Keep IPv4 CIDRs paired with IPv4 masks and IPv6 with IPv6 in calculated_remotes","Compare Addr().BitLen() of mask and cidr before submitting config","When migrating overlay networks between families, update both cidr keys and masks together"],"tags":["nebula","config","ipv4","ipv6","calculated-remotes"],"backgroundTag":"cidr-address-family-mismatch","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}