{"record":{"id":"353ba5fd5f76b96b","repo":"slimtoolkit/slim","slug":"invalid-expose-format-s","errorCode":null,"errorMessage":"invalid EXPOSE format: %s","messagePattern":"invalid EXPOSE format: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/app/master/command/clifvparser.go","lineNumber":61,"sourceCode":"\t\tcase true:\n\t\t\treturn DefaultStateArchiveVolumeName\n\t\tdefault:\n\t\t\treturn \"\"\n\t\t}\n\tcase \"off\":\n\t\treturn \"\"\n\tdefault:\n\t\treturn flag //should validate if it can be a Docker volume name\n\t}\n}\n\n// based on expose opt parsing in Docker\nfunc ParseDockerExposeOpt(values []string) (map[docker.Port]struct{}, error) {\n\texposedPorts := map[docker.Port]struct{}{}\n\n\tfor _, raw := range values {\n\t\tif strings.Contains(raw, \":\") {\n\t\t\treturn nil, fmt.Errorf(\"invalid EXPOSE format: %s\", raw)\n\t\t}\n\n\t\tproto, ports := nat.SplitProtoPort(raw)\n\t\tstartPort, endPort, err := nat.ParsePortRange(ports)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid port range in EXPOSE: %s / error: %s\", raw, err)\n\t\t}\n\n\t\tfor i := startPort; i <= endPort; i++ {\n\t\t\tportInfo, err := nat.NewPort(proto, strconv.FormatUint(i, 10))\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\n\t\t\texposedPorts[docker.Port(portInfo)] = struct{}{}\n\t\t}\n\t}\n\treturn exposedPorts, nil","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/slimtoolkit/slim/blob/81940d17fa112cc678e32209214bcb2355cb3004/pkg/app/master/command/clifvparser.go#L43-L79","documentation":"ParseDockerExposeOpt returns 'invalid EXPOSE format: %s' when an EXPOSE value contains a colon. Docker EXPOSE semantics allow only proto/port specifiers (e.g. '80', '8080/udp'); host-port mappings with colons belong to -p, not EXPOSE. The parser rejects such values up front.","triggerScenarios":"Calling ParseDockerExposeOpt (via GetContainerOverrides) with values like '8080:80' or '127.0.0.1:80:80' that contain ':'.","commonSituations":"Users copying docker run -p publish syntax into the expose option; confusion between EXPOSE (documentation metadata) and publish (actual port mapping); automated config generated from publish rules.","solutions":["Remove the colon/host part: use the container-side port only, e.g. '80' instead of '8080:80'.","Move host mappings to the publish-port option, which is parsed by ParsePortBindings.","Keep protocol suffixes if needed: '53/udp' is valid; '53:53/udp' is not.","Validate expose values in your config generator to reject ':' before reaching this parser."],"exampleFix":"// before\nexpose := []string{\"8080:80\"}\n// after\nexpose := []string{\"8080\"}\npublish := []string{\"8080:80\"} // handled by ParsePortBindings","handlingStrategy":"validation","validationCode":"for _, v := range exposeValues {\n    if strings.Contains(v, \":\") {\n        return fmt.Errorf(\"EXPOSE value %q must not contain ':'; use publish for host mappings\", v)\n    }\n}","typeGuard":null,"tryCatchPattern":"ports, err := command.ParseDockerExposeOpt(values)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid EXPOSE format\") {\n        return fmt.Errorf(\"use publish-port for host mappings: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep EXPOSE values as bare container ports, optionally with /proto.","Route host:container mappings to publish-port options instead.","Reject ':' in expose inputs at config validation time.","Educate users on EXPOSE vs -p semantics."],"tags":["docker","ports","cli-parsing"],"backgroundTag":"invalid-port-syntax","analyzedSha":"81940d17fa112cc678e32209214bcb2355cb3004","analyzedAt":"2026-08-31T23:06:12.682Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}