{"record":{"id":"0f461110ff2483fa","repo":"hashicorp/nomad","slug":"can-only-parse-single-port-numbers-or-port-ranges","errorCode":null,"errorMessage":"can only parse single port numbers or port ranges (ex. 80,100-120,150)","messagePattern":"can only parse single port numbers or port ranges \\(ex\\. 80,100-120,150\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/funcs.go","lineNumber":559,"sourceCode":"\n\t\t\t// Full range validation is below but prevent creating\n\t\t\t// arbitrarily large arrays here\n\t\t\tif start == 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"port must be > 0\")\n\t\t\t}\n\t\t\tif end > MaxValidPort {\n\t\t\t\treturn nil, fmt.Errorf(\"port must be < %d but found %d\", MaxValidPort, end)\n\t\t\t}\n\t\t\tcount += int(end - start)\n\t\t\tif count > MaxValidPort {\n\t\t\t\treturn nil, fmt.Errorf(\"maximum of %d ports can be reserved\", MaxValidPort)\n\t\t\t}\n\t\t\tports = slices.Grow(ports, int(end-start))\n\t\t\tfor i := start; i <= end; i++ {\n\t\t\t\tports = append(ports, i)\n\t\t\t}\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"can only parse single port numbers or port ranges (ex. 80,100-120,150)\")\n\t\t}\n\t}\n\n\treturn ports, nil\n}\n\n// ParentIDFromJobID returns the parent job ID of a given dispatch or periodic\n// job. Generally you should use the child job's Job.ParentID field instead, but\n// this is useful for contexts where the Job struct isn't present.\nfunc ParentIDFromJobID(jobID string) string {\n\tif strings.Index(jobID, \"/\") == 0 {\n\t\t// do a cheap O(n) check first before we do the more expensive Cut\n\t\t// method\n\t\treturn jobID\n\t}\n\tjobID, _, _ = strings.Cut(jobID, DispatchLaunchSuffix)\n\tjobID, _, _ = strings.Cut(jobID, PeriodicLaunchSuffix)\n\treturn jobID","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/funcs.go#L541-L577","documentation":"ParsePortRanges encountered a port spec segment with more than two hyphen-separated parts; only single ports and `start-end` ranges (e.g. 80,100-120,150) are accepted.","triggerScenarios":"Passing a malformed component like \"80-90-100\" or \"80--100\" (three or zero range parts) to ParsePortRanges.","commonSituations":"Extra dash typos in HCL job files, copy-paste errors, or tooling that joins ranges with the wrong separator.","solutions":["Rewrite the port spec using only single ports and two-value ranges","Check for stray hyphens or malformed segments in the input"],"exampleFix":"// before\nports = \"80-90-100\"\n// after\nports = \"80-100\"","handlingStrategy":"validation","validationCode":"for _, part := range strings.Split(spec, \",\") {\n  n := strings.Count(part, \"-\")\n  if n != 0 && n != 1 {\n    return fmt.Errorf(\"component %q must be a port or start-end range\", part)\n  }\n}","typeGuard":null,"tryCatchPattern":"ports, err := structs.ParsePortRanges(spec)\nif err != nil && strings.Contains(err.Error(), \"can only parse single port\") {\n  return fmt.Errorf(\"malformed port component in %q: %w\", spec, err)\n}","preventionTips":["Format port specs as N or N-M only","Avoid ad-hoc string building of ranges","Lint job files with regex ^\\d+(-\\d+)?(,\\d+(-\\d+)?)*$"],"tags":["nomad","ports","validation","parsing"],"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"}