{"record":{"id":"a6b731cfa88066d0","repo":"dagger/dagger","slug":"llbtodagger-invalid-exposed-port-q-w","errorCode":null,"errorMessage":"llbtodagger: invalid exposed port %q: %w","messagePattern":"llbtodagger: invalid exposed port %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/llbtodagger/metadata.go","lineNumber":65,"sourceCode":"\t\t)\n\t}\n\n\tlabelKeys := sortedMapKeys(cfg.Labels)\n\tfor _, key := range labelKeys {\n\t\tctrID = appendCall(\n\t\t\tctrID,\n\t\t\tcontainerType(),\n\t\t\t\"withLabel\",\n\t\t\targString(\"name\", key),\n\t\t\targString(\"value\", cfg.Labels[key]),\n\t\t)\n\t}\n\n\texposedPorts := sortedMapKeys(cfg.ExposedPorts)\n\tfor _, raw := range exposedPorts {\n\t\tport, proto, err := parseExposedPort(raw)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"llbtodagger: invalid exposed port %q: %w\", raw, err)\n\t\t}\n\t\tctrID = appendCall(\n\t\t\tctrID,\n\t\t\tcontainerType(),\n\t\t\t\"withExposedPort\",\n\t\t\targInt(\"port\", int64(port)),\n\t\t\targEnum(\"protocol\", proto),\n\t\t)\n\t}\n\n\tif cfg.Entrypoint == nil {\n\t\tctrID = appendCall(\n\t\t\tctrID,\n\t\t\tcontainerType(),\n\t\t\t\"withoutEntrypoint\",\n\t\t\targBool(\"keepDefaultArgs\", true),\n\t\t)\n\t} else {","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/util/llbtodagger/metadata.go#L47-L83","documentation":"Each key of the config's ExposedPorts map must parse as <port> or <port>/<tcp|udp>. parseExposedPort validates the numeric port and protocol; any failure (non-numeric port, out-of-range port, unknown protocol) is wrapped with this message identifying the raw key.","triggerScenarios":"An ExposedPorts map key like \"8080/http\", \"foo/tcp\", \"99999\", or \"0\" present in the image config while applyDockerImageConfig converts an image source.","commonSituations":"Hand-crafted or corrupted OCI manifests with unusual EXPOSE syntax; images imported from foreign registries with nonstandard port notation; typos in generated configs (e.g. \"8.0.0.0/tcp\").","solutions":["Correct the ExposedPorts key in the image config to \"<1-65535>\" optionally followed by \"/tcp\" or \"/udp\" and re-push","Inspect the image with crane config or docker inspect to find the offending port key","Rebuild the image from source with valid EXPOSE instructions"],"exampleFix":"// before (image config)\n\"ExposedPorts\": {\"8080/http\": {}}\n// after\n\"ExposedPorts\": {\"8080/tcp\": {}}","handlingStrategy":"validation","validationCode":"cfg, _ := crane.Config(ctx, ref)\nre := regexp.MustCompile(`^(\\d+)(/(tcp|udp))?$`)\nfor p := range cfg.ExposedPorts {\n    m := re.FindStringSubmatch(p)\n    if m == nil || n, _ := strconv.Atoi(m[1]); n < 1 || n > 65535 {\n        return fmt.Errorf(\"image %s has invalid exposed port %q\", ref, p)\n    }\n}","typeGuard":"var exposedPortRe = regexp.MustCompile(`^([1-9]\\d*/?(tcp|udp)?|0*)`)\nfunc validExposedPortKey(raw string) bool {\n    port, proto, ok := strings.Cut(raw, \"/\")\n    if ok && !strings.EqualFold(proto, \"tcp\") && !strings.EqualFold(proto, \"udp\") {\n        return false\n    }\n    n, err := strconv.Atoi(port)\n    return err == nil && n >= 1 && n <= 65535\n}","tryCatchPattern":"ctr, err := client.Container().From(ctx, ref)\nif err != nil && strings.Contains(err.Error(), \"invalid exposed port\") {\n    return fmt.Errorf(\"image %s declares an unusable exposed port: %w\", ref, err)\n}","preventionTips":["Only use \"<port>\" , \"<port>/tcp\" or \"<port>/udp\" in EXPOSE-style config","Validate manifests with a schema linter before publishing to your registry","Avoid third-party tools that write nonstandard port notations"],"tags":["docker","ports","image-config","validation"],"backgroundTag":"invalid-exposed-port","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}