openimsdk/open-im-server · warning

prommetrics %s %w

Error message

prommetrics %s %w

What it means

When the prometheus metrics server goroutine terminates for any reason, it cancels the whole RPC start context with a cause formatted as 'prommetrics <rpcRegisterName> <underlying error>'. This error string is the shutdown reason surfaced through context.Cause — the metrics server exiting is treated as fatal for the process.

Source

Thrown at pkg/common/startrpc/start.go:202

		}
		log.ZDebug(ctx, "prometheus start", "addr", prometheusListener.Addr(), "rpcRegisterName", rpcRegisterName)
		target, err := jsonutil.JsonMarshal(prommetrics.BuildDefaultTarget(registerIP, prometheusPort))
		if err != nil {
			return err
		}
		if autoSetPorts {
			if err = client.SetWithLease(ctx, prommetrics.BuildDiscoveryKey(rpcRegisterName, index), target, prommetrics.TTL); err != nil {
				if !errors.Is(err, discovery.ErrNotSupported) {
					return err
				}
			}
		}
		go func() {
			err := prommetrics.Start(prometheusListener)
			if err == nil {
				err = fmt.Errorf("listener done")
			}
			cancel(fmt.Errorf("prommetrics %s %w", rpcRegisterName, err))
		}()
	}

	var (
		rpcServer       *grpc.Server
		rpcGracefulStop chan struct{}
	)

	onGrpcServiceRegistrar := func(desc *grpc.ServiceDesc, impl any) {
		if rpcServer != nil {
			rpcServer.RegisterService(desc, impl)
			return
		}
		var rpcListenAddr string
		if autoSetPorts {
			rpcListenAddr = net.JoinHostPort(listenIP, "0")
		} else {
			rpcPort, err := datautil.GetElemByIndex(rpcPorts, index)

View on GitHub (pinned to 175a7bb067)

Solutions

  1. Read the wrapped underlying error after 'prommetrics <name>' — it names the actual Serve failure (e.g. 'address already in use').
  2. Check that prometheusListenAddr is free and not duplicated across RPC services on the same host.
  3. Determine whether the metrics server exiting should be fatal; if not, log instead of calling cancel.
  4. Verify graceful shutdown closes the metrics listener deliberately and handles http.ErrServerClosed so normal teardown doesn't produce this error.

Example fix

// before
err := prommetrics.Start(prometheusListener)
cancel(fmt.Errorf("prommetrics %s %w", rpcRegisterName, err))
// after
err := prommetrics.Start(prometheusListener)
if errors.Is(err, http.ErrServerClosed) {
    return
}
cancel(fmt.Errorf("prommetrics %s %w", rpcRegisterName, err))
Defensive patterns

Strategy: try-catch

Validate before calling

ln, err := net.Listen("tcp", prometheusListenAddr)
if err != nil { /* port taken; fail fast before starting RPC */ }

Try / catch

if cause := context.Cause(ctx); cause != nil && strings.HasPrefix(cause.Error(), "prommetrics ") {
    log.Error("metrics server failure shut down process", "cause", cause)
}

Prevention

When it happens

Trigger: prommetrics.Start(prometheusListener) returns an error (port binding failure at Serve time, listener closed, handler panic) inside the Start goroutine, cancelling the root context.

Common situations: Prometheus port already in use by another process; metrics listener becomes unusable at runtime; startup racing where the listener was closed early; intentional shutdown being misread as a failure.

Related errors


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