dagger/dagger · error
llbtodagger: invalid exposed port %q: %w
Error message
llbtodagger: invalid exposed port %q: %w
What it means
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.
Source
Thrown at util/llbtodagger/metadata.go:65
)
}
labelKeys := sortedMapKeys(cfg.Labels)
for _, key := range labelKeys {
ctrID = appendCall(
ctrID,
containerType(),
"withLabel",
argString("name", key),
argString("value", cfg.Labels[key]),
)
}
exposedPorts := sortedMapKeys(cfg.ExposedPorts)
for _, raw := range exposedPorts {
port, proto, err := parseExposedPort(raw)
if err != nil {
return nil, fmt.Errorf("llbtodagger: invalid exposed port %q: %w", raw, err)
}
ctrID = appendCall(
ctrID,
containerType(),
"withExposedPort",
argInt("port", int64(port)),
argEnum("protocol", proto),
)
}
if cfg.Entrypoint == nil {
ctrID = appendCall(
ctrID,
containerType(),
"withoutEntrypoint",
argBool("keepDefaultArgs", true),
)
} else {View on GitHub (pinned to 82ba2681db)
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
Example fix
// before (image config)
"ExposedPorts": {"8080/http": {}}
// after
"ExposedPorts": {"8080/tcp": {}} Defensive patterns
Strategy: validation
Validate before calling
cfg, _ := crane.Config(ctx, ref)
re := regexp.MustCompile(`^(\d+)(/(tcp|udp))?$`)
for p := range cfg.ExposedPorts {
m := re.FindStringSubmatch(p)
if m == nil || n, _ := strconv.Atoi(m[1]); n < 1 || n > 65535 {
return fmt.Errorf("image %s has invalid exposed port %q", ref, p)
}
} Type guard
var exposedPortRe = regexp.MustCompile(`^([1-9]\d*/?(tcp|udp)?|0*)`)
func validExposedPortKey(raw string) bool {
port, proto, ok := strings.Cut(raw, "/")
if ok && !strings.EqualFold(proto, "tcp") && !strings.EqualFold(proto, "udp") {
return false
}
n, err := strconv.Atoi(port)
return err == nil && n >= 1 && n <= 65535
} Try / catch
ctr, err := client.Container().From(ctx, ref)
if err != nil && strings.Contains(err.Error(), "invalid exposed port") {
return fmt.Errorf("image %s declares an unusable exposed port: %w", ref, err)
} Prevention
- 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
When it happens
Trigger: An ExposedPorts map key like "8080/http", "foo/tcp", "99999", or "0" present in the image config while applyDockerImageConfig converts an image source.
Common situations: 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").
Related errors
- port %d out of range
- llbtodagger: invalid image config env entry %q
- unsupported protocol %q
- no ports specified
- port mapping %q: expected host:container
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/a6b731cfa88066d0.
Report an issue: GitHub.