slackhq/nebula · error
already listening on port %d
Error message
already listening on port %d
What it means
Each Service keeps a registry of active listeners keyed by port under its mutex. Listen rejects a bind attempt when a listener already occupies the requested port, mirroring an EADDRINUSE from a real kernel. The port must be unique for the lifetime of the Service.
Source
Thrown at service/service.go:240
return nil, errors.New("specific port required, got 0")
}
if addr.Port < 0 || addr.Port >= math.MaxUint16 {
return nil, fmt.Errorf("invalid port %d", addr.Port)
}
port := uint16(addr.Port)
l := &tcpListener{
port: port,
s: s,
addr: addr,
accept: make(chan net.Conn),
}
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.mu.listeners[port]; ok {
return nil, fmt.Errorf("already listening on port %d", port)
}
s.mu.listeners[port] = l
return l, nil
}
func (s *Service) Wait() error {
return s.eg.Wait()
}
func (s *Service) Close() error {
s.control.Stop()
return nil
}
func (s *Service) tcpHandler(r *tcp.ForwarderRequest) {
endpointID := r.ID()
View on GitHub (pinned to dd8f660c0a)
Solutions
- Close the existing listener (l.Close()) before listening on the same port again.
- Use a different port for the new listener.
- Create a new Service instance if you need an isolated port table.
Example fix
// before
l2, err := svc.Listen("tcp", ":8080") // already listening
// after
l1.Close()
l2, err := svc.Listen("tcp", ":8080") Defensive patterns
Strategy: try-catch
Validate before calling
if activeListeners[port] {
return fmt.Errorf("port %d already bound by our own listener", port)
} Try / catch
l, err := svc.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
if strings.Contains(err.Error(), "already listening on port") {
// treat as EADDRINUSE: close stale listener or pick another port
return ErrPortInUse
}
return err
} Prevention
- Always defer listener Close() in tests via t.Cleanup(func(){ l.Close() }).
- Centralize listener creation so the same port can't be requested twice.
- Prefer dynamic port selection per Service instance in parallel tests.
When it happens
Trigger: Calling Service.Listen twice with the same wildcard port, e.g. Listen("tcp", ":8080") while a previous tcpListener on 8080 is still registered (service/service.go:240).
Common situations: Restarting a test server without closing the old listener; two test helpers both binding the same fixed port; forgetting to call Close() on the previous listener before rebinding; parallel tests sharing one Service.
Related errors
- only wildcard address supported, got %q %v
- invalid port %d
- unknown network type: %s
- could not enable TCP SACK: %v
- could not create netstack NIC: %v
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/519a6d441e82d994.
Report an issue: GitHub.