sipeed/picoclaw · error
port cannot be empty
Error message
port cannot be empty
What it means
netbind.OpenPlan rejects an empty port string before opening any listeners. Port must be a non-empty string; "0" is the explicit way to request an ephemeral port (OpenPlan latches the OS-assigned port from the first group when port=="0").
Source
Thrown at pkg/netbind/netbind.go:317
seenExact[key] = struct{}{}
groups = append(groups, bindGroup{
kind: groupExact,
exact: exactBinding{
host: token.canonical,
network: "tcp",
},
})
}
}
plan := Plan{groups: groups}
plan.ProbeHost = probeHostForGroups(groups)
return plan, nil
}
func OpenPlan(plan Plan, port string) (OpenResult, error) {
if port == "" {
return OpenResult{}, errors.New("port cannot be empty")
}
selectedPort := port
listeners := make([]net.Listener, 0, len(plan.groups))
bindHosts := make([]string, 0, len(plan.groups))
bindSeen := make(map[string]struct{}, len(plan.groups))
closeAll := func() {
for _, ln := range listeners {
_ = ln.Close()
}
}
for _, group := range plan.groups {
groupListeners, groupHosts, actualPort, err := openGroup(group, selectedPort)
if err != nil {
closeAll()
return OpenResult{}, errView on GitHub (pinned to 49183d7e8d)
Solutions
- Pass "0" when you want the OS to pick a free port
- Pass the concrete port string from config (e.g. "8000")
- If port comes from an int, map 0 to "0": port := strconv.Itoa(cfg.Port)
Example fix
// before
res, err := netbind.OpenPlan(plan, cfg.BindPort) // cfg.BindPort == ""
// after
port := cfg.BindPort
if port == "" { port = "0" } // ephemeral
res, err := netbind.OpenPlan(plan, port) Defensive patterns
Strategy: validation
Validate before calling
port := strings.TrimSpace(cfg.BindPort)
if port == "" {
port = "0" // ephemeral
}
res, err := netbind.OpenPlan(plan, port) Try / catch
res, err := netbind.OpenPlan(plan, port)
if err != nil {
if err.Error() == "port cannot be empty" { /* fix port source, not a runtime condition */ }
return err
} Prevention
- Normalize empty port to "0" at the config layer, not at the bind layer
- When converting int ports, handle 0 explicitly with strconv.Itoa
- Unit-test the binder with the exact config values production sends
When it happens
Trigger: OpenPlan(plan, "") — typically a config field (port unset/empty) or a zero-valued variable formatted to "" instead of "0" being passed straight through.
Common situations: Config schema allows an omitted port and the empty string reaches the binder; code converting an int port to string skips the 0 case; tests constructing a Plan manually and forgetting the port.
Related errors
- host cannot be empty
- host list contains an empty entry
- invalid --host value: %w
- ${label} must be a JSON object.
- ${label}.${key} must be a string.
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/6e408039de431a8d.
Report an issue: GitHub.