{"record":{"id":"498f812fbcb4c492","repo":"nektos/act","slug":"invalid-range-format-for-expose-w","errorCode":null,"errorMessage":"invalid range format for --expose: %w","messagePattern":"invalid range format for --expose: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/container/docker_cli.go","lineNumber":481,"sourceCode":"\t}\n\n\t// Add published ports as exposed ports.\n\texposedPorts := network.PortSet{}\n\tfor port := range ports {\n\t\tp, err := network.ParsePort(string(port))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\texposedPorts[p] = struct{}{}\n\t}\n\n\t// Merge in exposed ports to the map of published ports\n\tfor _, e := range copts.expose.GetSlice() {\n\t\t// support two formats for expose, original format <portnum>/[<proto>]\n\t\t// or <startport-endport>/[<proto>]\n\t\tpr, err := network.ParsePortRange(e)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid range format for --expose: %w\", err)\n\t\t}\n\t\t// parse the start and end port and create a sequence of ports to expose\n\t\t// if expose a port, the start and end port are the same\n\t\tfor p := range pr.All() {\n\t\t\texposedPorts[p] = struct{}{}\n\t\t}\n\t}\n\n\t// validate and parse device mappings. Note we do late validation of the\n\t// device path (as opposed to during flag parsing), as at the time we are\n\t// parsing flags, we haven't yet sent a _ping to the daemon to determine\n\t// what operating system it is.\n\tdevices := copts.devices.GetSlice()\n\tdeviceMappings := make([]container.DeviceMapping, 0, len(devices))\n\tcdiDeviceNames := make([]string, 0, len(devices))\n\tfor _, device := range devices {\n\t\tif cdi.IsQualifiedName(device) {\n\t\t\tcdiDeviceNames = append(cdiDeviceNames, device)","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/nektos/act/blob/4f411281417e88660bea1c1a1749aa71ae0bd60f/pkg/container/docker_cli.go#L463-L499","documentation":"Values from --expose may be a single port with optional protocol (<port>/tcp) or a range (<start>-<end>/tcp). Each entry is parsed with network.ParsePortRange; invalid syntax — non-numeric ports, reversed ranges (9000-80), out-of-range port numbers (>65535), or malformed protocol suffixes — fails with this wrapped error.","triggerScenarios":"Passing --expose in container/job options such as '--expose 80-8080-tcp', '--expose tcp://80', '--expose 70000', or '--expose 8080-80'. Parsing happens client-side in act's container option parser before any daemon call.","commonSituations":"Confusing --expose with -p publish syntax (protocol://host:container forms); ranges written high-low; copy-paste from firewall rules using 65536+ values; YAML coercing '80' to something unexpected.","solutions":["Use plain '<port>' or '<start>-<end>' with optional '/tcp' or '/udp': --expose 8080 or --expose 3000-3005/tcp","Fix reversed ranges to low-high","Keep ports within 1-65535","Remember --expose only opens the port inside the container network; use -p for host publishing"],"exampleFix":"# before\noptions: --expose 8080-80\n\n# after\noptions: --expose 80-8080/tcp","handlingStrategy":"validation","validationCode":"for _, e := range exposeList {\n    if _, err := network.ParsePortRange(e); err != nil {\n        return fmt.Errorf(\"bad --expose value %q: %w\", e, err)\n    }\n}","typeGuard":"func isValidExpose(s string) bool {\n    _, err := network.ParsePortRange(s)\n    return err == nil\n}","tryCatchPattern":null,"preventionTips":["Use <port> or <start>-<end> with optional /tcp|/udp only","Keep ranges low-high and ports <= 65535","Don't reuse firewall or URL-style port syntax in --expose"],"tags":["docker","ports","expose","validation","act"],"backgroundTag":null,"analyzedSha":"4f411281417e88660bea1c1a1749aa71ae0bd60f","analyzedAt":"2026-08-15T09:19:46.307Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}