openimsdk/open-im-server · error

prometheus listen %d error %w

Error message

prometheus listen %d error %w

What it means

When Prometheus metrics are enabled, run() asks the kernel for a TCP listener on the configured port via net.Listen. If the OS refuses (port already bound, no permission, invalid port), the underlying error is wrapped as 'prometheus listen %d error %w'. The process cannot export metrics and startup fails.

Source

Thrown at cmd/main.go:289

	go func() {
		<-ctx.Done()
		log.ZError(ctx, "context server exit cause", context.Cause(ctx))
	}()

	if prometheus := x.config.API.Prometheus; prometheus.Enable {
		var (
			port int
			err  error
		)
		if !prometheus.AutoSetPorts {
			port, err = datautil.GetElemByIndex(prometheus.Ports, 0)
			if err != nil {
				return err
			}
		}
		listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
		if err != nil {
			return fmt.Errorf("prometheus listen %d error %w", port, err)
		}
		defer listener.Close()
		log.ZDebug(ctx, "prometheus start", "addr", listener.Addr())
		go func() {
			err := prommetrics.Start(listener)
			if err == nil {
				err = fmt.Errorf("http done")
			}
			cancel(fmt.Errorf("prometheus %w", err))
		}()
	}

	go func() {
		sigs := make(chan os.Signal, 1)
		signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
		select {
		case <-ctx.Done():
			return

View on GitHub (pinned to 175a7bb067)

Solutions

  1. Change the prometheus port in the component config to a free port and restart
  2. Find and stop the process occupying the port: lsof -i :PORT or ss -ltnp | grep PORT, then kill it
  3. If using a port <1024, run with CAP_NET_BIND_SERVICE or pick a high port
  4. Validate the configured port is 1-65535

Example fix

// before (config)
prometheus: { port: 9090 }   # already in use
// after
prometheus: { port: 19090 }  # free port
Defensive patterns

Strategy: try-catch

Validate before calling

func portFree(p int) bool {
	ln, err := net.Listen("tcp", fmt.Sprintf(":%d", p))
	if err != nil { return false }
	ln.Close()
	return true
}
// call portFree(cfg.Prometheus.Port) before startup and pick another port if false

Try / catch

if err := x.run(ctx); err != nil {
	var perr *net.OpError
	if errors.As(err, &perr) && strings.Contains(err.Error(), "prometheus listen") {
		log.ZError(ctx, "prometheus port busy, pick a free port", err)
		return
	}
	panic(err)
}

Prevention

When it happens

Trigger: Prometheus port in config is already used by another process (EADDRINUSE), the port is privileged (<1024) without root/CAP_NET_BIND_SERVICE, or the port value is invalid/out of range.

Common situations: Two OpenIM components on the same host configured with the same prometheus.port; a leftover zombie process holding the port; running in a container without permission to bind low ports; port 0 or >65535 in config.

Related errors


AI-assisted analysis of openimsdk/open-im-server@175a7bb067 (2026-09-04). Data as JSON: /api/errors/bc13fb4e1d129945. Report an issue: GitHub.