OpenNHP/opennhp · critical

listen error

Error message

listen error %v

What it means

net.ListenUDP failed while binding the configured IP:port, so Start aborts with this error wrapping the OS error. Common causes are port already in use, binding an IP not assigned to the host, or lacking privileges for low ports.

Solutions

  1. Check the port with ss -ulpn | grep <port> and stop the conflicting process
  2. Change listenPort in config.toml to a free port
  3. Verify listenIp is an IP assigned to a local interface
  4. Run as root or grant CAP_NET_BIND_SERVICE for privileged ports
  5. Wait for TIME_WAIT/lingering socket release and retry

Example fix

// before (config.toml)
listenPort = 62302 // already bound by old instance
// after
listenPort = 62303
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.ListenPacket("udp", fmt.Sprintf("%s:%d", cfg.ListenIp, cfg.ListenPort))
if err != nil { return fmt.Errorf("port unavailable: %w", err) }
conn.Close()

Try / catch

if err := server.Start(); err != nil {
    if strings.Contains(err.Error(), "listen error") {
        time.Sleep(retryDelay)
        return server.Start()
    }
    return err
}

Prevention

When it happens

Trigger: Another process (or a previous un-terminated instance) already holds ListenPort; ListenIp is not a local interface address; port <1024 without CAP_NET_BIND_SERVICE/root.

Common situations: Duplicate daemon instance after a failed restart; Docker/network namespace port conflicts; config pointing at a container-internal IP that doesn't exist in the host namespace.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/755c5d58ca373e23. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/server/udpserver.go:252

	var netIP net.IP
	if len(s.config.ListenIp) > 0 {
		netIP = net.ParseIP(s.config.ListenIp)
		if netIP == nil {
			log.Error("udp listen ip address is incorrect!")
			return fmt.Errorf("udp listen ip address is incorrect")
		}
	} else {
		netIP = net.IPv4zero // will both listen on ipv4 0.0.0.0:port and ipv6 [::]:port
	}

	s.listenConn, err = net.ListenUDP("udp", &net.UDPAddr{
		IP:   netIP,
		Port: s.config.ListenPort,
	})
	if err != nil {
		log.Error("listen error: %v", err)
		return fmt.Errorf("listen error %v", err)
	}

	// retrieve local port
	laddr := s.listenConn.LocalAddr()
	s.listenAddr, err = net.ResolveUDPAddr(laddr.Network(), laddr.String())
	if err != nil {
		log.Error("resolve local UDPAddr error: %v", err)
		return fmt.Errorf("resolve UDPAddr error %v", err)
	}

	prk, err := base64.StdEncoding.DecodeString(s.config.PrivateKeyBase64)
	if err != nil {
		log.Error("private key parse error: %v", err)
		return fmt.Errorf("private key parse error %v", err)
	}

	option := &core.DeviceOptions{
		DisableAgentPeerValidation: s.config.DisableAgentValidation,

View on GitHub (pinned to 6e04ca5ff0)