{"record":{"id":"9506333190167a83","repo":"slackhq/nebula","slug":"missing-port-v","errorCode":null,"errorMessage":"missing port: %v","messagePattern":"missing port: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"calculated_remote.go","lineNumber":148,"sourceCode":"\t}\n\n\trawValue := rawMap[\"mask\"]\n\tif rawValue == nil {\n\t\treturn nil, fmt.Errorf(\"missing mask: %v\", rawMap)\n\t}\n\trawMask, ok := rawValue.(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"invalid mask (type %T): %v\", rawValue, rawValue)\n\t}\n\tmaskCidr, err := netip.ParsePrefix(rawMask)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid mask: %s\", rawMask)\n\t}\n\n\tvar port int\n\trawValue = rawMap[\"port\"]\n\tif rawValue == nil {\n\t\treturn nil, fmt.Errorf(\"missing port: %v\", rawMap)\n\t}\n\tswitch v := rawValue.(type) {\n\tcase int:\n\t\tport = v\n\tcase string:\n\t\tport, err = strconv.Atoi(v)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid port: %s: %w\", v, err)\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"invalid port (type %T): %v\", rawValue, rawValue)\n\t}\n\n\treturn newCalculatedRemote(cidr, maskCidr, port)\n}\n","sourceCodeStart":130,"sourceCodeEnd":164,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/calculated_remote.go#L130-L164","documentation":"This error is returned by newCalculatedRemotesEntryFromConfig when a calculated_remotes config entry has no 'port' key. A calculated remote entry must specify the UDP port that masked hosts will be dialed on; without it Nebula cannot build the entry and aborts config parsing.","triggerScenarios":"Calling newCalculatedRemotesListFromConfig with a calculated_remotes map entry that omits the 'port' key entirely (rawMap[\"port\"] is nil), e.g. only mask is provided.","commonSituations":"Users writing a calculated_remotes block assuming the port inherits from the lhouse/listen port, or copy-pasting partial example configs that omit the required port field.","solutions":["Add the required 'port' key to the calculated_remotes entry, e.g. port: 4242","Confirm the port matches the UDP port your lighthouses actually listen on","Review the Nebula calculated_remotes documentation for the required entry schema"],"exampleFix":"// before\ncalculated_remotes:\n  - mask: 10.0.0.0/8\n// after\ncalculated_remotes:\n  - mask: 10.0.0.0/8\n    port: 4242","handlingStrategy":"validation","validationCode":"func entryHasPort(entry map[string]any) bool {\n    v, ok := entry[\"port\"]\n    return ok && v != nil\n}\n// check every calculated_remotes entry before parsing","typeGuard":"func hasPort(m map[string]any) bool {\n    p, present := m[\"port\"]\n    return present && p != nil\n}","tryCatchPattern":"if err := newCalculatedRemotesListFromConfig(raw); err != nil {\n    if strings.Contains(err.Error(), \"missing port\") {\n        log.Fatalf(\"each calculated_remotes entry requires a port: %v\", err)\n    }\n    return err\n}","preventionTips":["Include port in every calculated_remotes entry template","Share a canonical config example so entries are never partially copied","Add a CI check that fails on calculated_remotes entries lacking a port key"],"tags":["config","yaml","port","network"],"backgroundTag":"missing-required-config-field","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"}