{"record":{"id":"5ae3dbe5818e8890","repo":"hashicorp/nomad","slug":"port-must-be-0","errorCode":null,"errorMessage":"port must be > 0","messagePattern":"port must be > 0","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/funcs.go","lineNumber":515,"sourceCode":"\t\treturn nil, nil\n\t}\n\n\tports := []uint64{}\n\tfor _, part := range parts {\n\t\tpart = strings.TrimSpace(part)\n\t\trangeParts := strings.Split(part, \"-\")\n\t\tl := len(rangeParts)\n\t\tswitch l {\n\t\tcase 1:\n\t\t\tif val := rangeParts[0]; val == \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"can't specify empty port\")\n\t\t\t} else {\n\t\t\t\tport, err := strconv.ParseUint(val, 10, 0)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tif port == 0 {\n\t\t\t\t\treturn nil, fmt.Errorf(\"port must be > 0\")\n\t\t\t\t}\n\t\t\t\tif port > MaxValidPort {\n\t\t\t\t\treturn nil, fmt.Errorf(\"port must be < %d but found %d\", MaxValidPort, port)\n\t\t\t\t}\n\t\t\t\tcount++\n\t\t\t\tif count > MaxValidPort {\n\t\t\t\t\treturn nil, fmt.Errorf(\"maximum of %d ports can be reserved\", MaxValidPort)\n\t\t\t\t}\n\t\t\t\tports = append(ports, port)\n\t\t\t}\n\t\tcase 2:\n\t\t\t// We are parsing a range\n\t\t\tstart, err := strconv.ParseUint(rangeParts[0], 10, 0)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\tend, err := strconv.ParseUint(rangeParts[1], 10, 0)","sourceCodeStart":497,"sourceCodeEnd":533,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/funcs.go#L497-L533","documentation":"ParsePortRanges rejects port 0: a single-token segment parsed successfully but the value is 0, and port 0 is not a reservable host port. Nomad requires explicit positive port numbers when reserving port ranges on a node.","triggerScenarios":"ParsePortRanges receives a segment like \"0\" (or the low end of a range being validated) and port == 0; raised during node SetNode/IsValidConfig validation of the reserved-ports list.","commonSituations":"Config templating that defaulted a port variable to 0; typos where '0' was written instead of a real port; misunderstanding that port 0 means 'auto-assign' (dynamic ports are handled differently in Nomad).","solutions":["Replace 0 with an explicit valid port number (1-65535)","If you want dynamic assignment, do not reserve the port — leave it out of reserved.ports and use a dynamic port label in the job","Fix the config source/variable that produced 0 (e.g. unset env var defaulting to 0)","Validate input with structs.ParsePortRanges before applying the node config"],"exampleFix":"// before\nreserved { ports = \"0,22\" }\n// after\nreserved { ports = \"8080,22\" }","handlingStrategy":"validation","validationCode":"// go: reject zero ports before validation pipeline\nfor _, p := range strings.Split(portSpec, \",\") {\n    if v, err := strconv.ParseUint(strings.TrimSpace(p), 10, 16); err == nil && v == 0 {\n        return errors.New(\"reserved ports must not include 0\")\n    }\n}","typeGuard":null,"tryCatchPattern":"if _, err := structs.ParsePortRanges(portSpec); err != nil {\n    if strings.Contains(err.Error(), \"port must be > 0\") {\n        return fmt.Errorf(\"remove 0 from reserved.ports; use dynamic ports for auto-assign\")\n    }\n    return err\n}","preventionTips":["Don't treat 0 as 'auto'; use dynamic port labels in jobs instead","Ensure config templates default unset port variables to a real port or omit them","Validate port configs in CI before deploying to clients"],"tags":["nomad","ports","validation","config"],"backgroundTag":"invalid-port-range","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}