crowdsecurity/crowdsec · error

could not listen on port %d: %w

Error message

could not listen on port %d: %w

What it means

The UDP address resolved but net.ListenUDP failed to bind the socket. Typical causes are the port already in use by another process, binding to an address not assigned to the machine, or lacking privileges for ports below 1024.

Source

Thrown at pkg/acquisition/modules/syslog/internal/server/syslogserver.go:32

	conn          *net.UDPConn
	Logger        *log.Entry
	MaxMessageLen int
}

type SyslogMessage struct {
	Message []byte
	Client  string
}

func (s *SyslogServer) Listen(listenAddr string, port int) error {
	udpAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(listenAddr, strconv.Itoa(port)))
	if err != nil {
		return fmt.Errorf("could not resolve addr %s: %w", listenAddr, err)
	}

	udpConn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		return fmt.Errorf("could not listen on port %d: %w", port, err)
	}

	s.Logger.Debugf("listening on %s:%d", listenAddr, port)
	s.conn = udpConn

	return nil
}

func (s *SyslogServer) Serve(ctx context.Context, msgChan chan SyslogMessage) error {
	go func() {
		<-ctx.Done()
		// closing the socket unblocks ReadFrom()
		s.conn.Close()
	}()

	// RFC3164 says 1024 bytes max
	// RFC5424 says 480 bytes minimum, and should support up to 2048 bytes
	buf := make([]byte, s.MaxMessageLen)

View on GitHub (pinned to 909b515798)

Solutions

  1. Stop the process already bound to that UDP port (e.g. disable rsyslog's UDP listener) or choose another port.
  2. For ports <1024, run crowdsec with elevated privileges or CAP_NET_BIND_SERVICE, or use a high port and forward with rsyslog.
  3. Verify the listen IP is assigned to the host (ip addr); use 0.0.0.0 to bind all interfaces.
  4. Read the wrapped OS error: 'address already in use' vs 'cannot assign requested address' distinguish the two cases.

Example fix

// before (config.yaml)
port: 514   # EACCES as non-root

// after
port: 5514  # or grant CAP_NET_BIND_SERVICE
Defensive patterns

Strategy: try-catch

Validate before calling

if port < 1024 && os.Geteuid() != 0 {
    return errors.New("binding ports <1024 requires root or CAP_NET_BIND_SERVICE")
}
// check availability
if conn, err := net.ListenPacket("udp", fmt.Sprintf("%s:%d", addr, port)); err == nil {
    conn.Close()
} else {
    return fmt.Errorf("udp port %d unavailable: %w", port, err)
}

Try / catch

if err := srv.Listen(addr, port); err != nil {
    if strings.Contains(err.Error(), "address already in use") {
        // stop competing daemon or pick another port
    }
    return err
}

Prevention

When it happens

Trigger: Stream() -> Listen() with a port already bound by another syslog daemon (rsyslog/syslog-ng), a listen IP not present on the host, or port 514 as an unprivileged user.

Common situations: Running crowdsec as non-root while wanting the standard syslog port 514; rsyslog already holding 514/udp; docker container where 0.0.0.0 bind address differs; typo'd listen IP.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/b395e44da493deb4. Report an issue: GitHub.