{"record":{"id":"fdf8c23c814eb374","repo":"caddyserver/caddy","slug":"end-port-must-not-be-less-than-start-port","errorCode":null,"errorMessage":"end port must not be less than start port","messagePattern":"end port must not be less than start port","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"listeners.go","lineNumber":362,"sourceCode":"\tvar start, end uint64\n\tif port == \"\" {\n\t\tstart = uint64(defaultPort)\n\t\tend = uint64(defaultPort)\n\t} else {\n\t\tbefore, after, found := strings.Cut(port, \"-\")\n\t\tif !found {\n\t\t\tafter = before\n\t\t}\n\t\tstart, err = strconv.ParseUint(before, 10, 16)\n\t\tif err != nil {\n\t\t\treturn NetworkAddress{}, fmt.Errorf(\"invalid start port: %v\", err)\n\t\t}\n\t\tend, err = strconv.ParseUint(after, 10, 16)\n\t\tif err != nil {\n\t\t\treturn NetworkAddress{}, fmt.Errorf(\"invalid end port: %v\", err)\n\t\t}\n\t\tif end < start {\n\t\t\treturn NetworkAddress{}, fmt.Errorf(\"end port must not be less than start port\")\n\t\t}\n\t\tif (end - start) > maxPortSpan {\n\t\t\treturn NetworkAddress{}, fmt.Errorf(\"port range exceeds %d ports\", maxPortSpan)\n\t\t}\n\t}\n\treturn NetworkAddress{\n\t\tNetwork:   network,\n\t\tHost:      host,\n\t\tStartPort: uint(start),\n\t\tEndPort:   uint(end),\n\t}, nil\n}\n\n// SplitNetworkAddress splits a into its network, host, and port components.\n// Note that port may be a port range (:X-Y), or omitted for unix sockets.\nfunc SplitNetworkAddress(a string) (network, host, port string, err error) {\n\tbeforeSlash, afterSlash, slashFound := strings.Cut(a, \"/\")\n\tif slashFound {","sourceCodeStart":344,"sourceCodeEnd":380,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/listeners.go#L344-L380","documentation":"After both ports parse, Caddy rejects ranges where end < start, e.g. 8090-8080. Port ranges in Caddy are ascending only, and both bounds are inclusive.","triggerScenarios":"Any address like ':8090-8080', ':443-80', or config generation that swaps min/max when a user enters an inverted range.","commonSituations":"Users writing 'high-low' naturally when they mean 'any port in this span'; automation that concatenates two user-supplied numbers without ordering them.","solutions":["Swap the bounds so the smaller port comes first: ':8080-8090'.","In generators, sort the pair before formatting the range.","A single port (no hyphen) avoids range-ordering issues entirely."],"exampleFix":"// before\n{\n  listen :8090-8080\n}\n// after\n{\n  listen :8080-8090\n}","handlingStrategy":"validation","validationCode":"func orderedRange(start, end uint64) (uint64, uint64) {\n    if end < start { return end, start }\n    return start, end\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Sort user-supplied port pairs in tooling before formatting ranges.","Prefer single ports unless a range is genuinely needed."],"tags":["port","port-range","validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}