{"record":{"id":"6c82ac7440522a23","repo":"netbirdio/netbird","slug":"empty-port","errorCode":null,"errorMessage":"empty port","messagePattern":"empty port","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/management/types/policy.go","lineNumber":258,"sourceCode":"\t\t}\n\t\tif start > end {\n\t\t\treturn RulePortRange{}, fmt.Errorf(\"invalid port range: start %d > end %d\", start, end)\n\t\t}\n\t\treturn RulePortRange{Start: uint16(start), End: uint16(end)}, nil\n\t}\n\n\tp, err := parsePort(portStr)\n\tif err != nil {\n\t\treturn RulePortRange{}, err\n\t}\n\n\treturn RulePortRange{Start: uint16(p), End: uint16(p)}, nil\n}\n\nfunc parsePort(portStr string) (int, error) {\n\n\tif portStr == \"\" {\n\t\treturn 0, errors.New(\"empty port\")\n\t}\n\tp, err := strconv.Atoi(portStr)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"invalid port %q: %w\", portStr, err)\n\t}\n\tif p < 1 || p > 65535 {\n\t\treturn 0, fmt.Errorf(\"port out of range (1–65535): %d\", p)\n\t}\n\treturn p, nil\n}\n","sourceCodeStart":240,"sourceCodeEnd":269,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/shared/management/types/policy.go#L240-L269","documentation":"parsePort rejects an empty port string. It is reached from ParseRuleString when the rule has a protocol, a '/', and nothing after it (e.g. \"tcp/\"), because strings.Split keeps the empty segment and TrimSpace leaves it empty. Valid ports must parse as integers in 1-65535.","triggerScenarios":"Rules like \"tcp/\" or \"udp/ \" with a missing or whitespace-only port; template strings such as tcp/${PORT} with the variable unset.","commonSituations":"Unfilled template placeholders in generated configs; truncated rule strings from imports; trailing-slash typos.","solutions":["Add a concrete port, e.g. tcp/443","Use 'all' instead of 'tcp/' when all traffic is intended","Validate generated rule strings before submitting them to the API"],"exampleFix":"// before\nproto, ports, err := types.ParseRuleString(\"tcp/\")\n\n// after\nproto, ports, err := types.ParseRuleString(\"tcp/443\")","handlingStrategy":"validation","validationCode":"parts := strings.Split(rule, \"/\")\nif len(parts) == 2 && strings.TrimSpace(parts[1]) == \"\" {\n\treturn fmt.Errorf(\"rule %q is missing its port\", rule)\n}","typeGuard":"func hasPortSegment(rule string) bool {\n\tparts := strings.Split(strings.TrimSpace(rule), \"/\")\n\treturn len(parts) != 2 || strings.TrimSpace(parts[1]) != \"\"\n}","tryCatchPattern":"if _, _, err := types.ParseRuleString(rule); err != nil {\n\tif err.Error() == \"empty port\" {\n\t\t// unfilled template placeholder; surface config error to the user\n\t}\n}","preventionTips":["Fail template rendering when port variables are unset","Validate generated rule strings before API submission","Trim inputs and reject trailing slashes at the form layer"],"tags":["policy","validation","ports","parsing"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}