{"record":{"id":"cff007092804cac8","repo":"openimsdk/open-im-server","slug":"prommetrics-s-w","errorCode":null,"errorMessage":"prommetrics %s %w","messagePattern":"prommetrics (.+?) %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/common/startrpc/start.go","lineNumber":202,"sourceCode":"\t\t}\n\t\tlog.ZDebug(ctx, \"prometheus start\", \"addr\", prometheusListener.Addr(), \"rpcRegisterName\", rpcRegisterName)\n\t\ttarget, err := jsonutil.JsonMarshal(prommetrics.BuildDefaultTarget(registerIP, prometheusPort))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif autoSetPorts {\n\t\t\tif err = client.SetWithLease(ctx, prommetrics.BuildDiscoveryKey(rpcRegisterName, index), target, prommetrics.TTL); err != nil {\n\t\t\t\tif !errors.Is(err, discovery.ErrNotSupported) {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgo func() {\n\t\t\terr := prommetrics.Start(prometheusListener)\n\t\t\tif err == nil {\n\t\t\t\terr = fmt.Errorf(\"listener done\")\n\t\t\t}\n\t\t\tcancel(fmt.Errorf(\"prommetrics %s %w\", rpcRegisterName, err))\n\t\t}()\n\t}\n\n\tvar (\n\t\trpcServer       *grpc.Server\n\t\trpcGracefulStop chan struct{}\n\t)\n\n\tonGrpcServiceRegistrar := func(desc *grpc.ServiceDesc, impl any) {\n\t\tif rpcServer != nil {\n\t\t\trpcServer.RegisterService(desc, impl)\n\t\t\treturn\n\t\t}\n\t\tvar rpcListenAddr string\n\t\tif autoSetPorts {\n\t\t\trpcListenAddr = net.JoinHostPort(listenIP, \"0\")\n\t\t} else {\n\t\t\trpcPort, err := datautil.GetElemByIndex(rpcPorts, index)","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/openimsdk/open-im-server/blob/175a7bb0673eca18e9d1b10bff4f728da6b1b513/pkg/common/startrpc/start.go#L184-L220","documentation":"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.","triggerScenarios":"prommetrics.Start(prometheusListener) returns an error (port binding failure at Serve time, listener closed, handler panic) inside the Start goroutine, cancelling the root context.","commonSituations":"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.","solutions":["Read the wrapped underlying error after 'prommetrics <name>' — it names the actual Serve failure (e.g. 'address already in use').","Check that prometheusListenAddr is free and not duplicated across RPC services on the same host.","Determine whether the metrics server exiting should be fatal; if not, log instead of calling cancel.","Verify graceful shutdown closes the metrics listener deliberately and handles http.ErrServerClosed so normal teardown doesn't produce this error."],"exampleFix":"// before\nerr := prommetrics.Start(prometheusListener)\ncancel(fmt.Errorf(\"prommetrics %s %w\", rpcRegisterName, err))\n// after\nerr := prommetrics.Start(prometheusListener)\nif errors.Is(err, http.ErrServerClosed) {\n    return\n}\ncancel(fmt.Errorf(\"prommetrics %s %w\", rpcRegisterName, err))","handlingStrategy":"try-catch","validationCode":"ln, err := net.Listen(\"tcp\", prometheusListenAddr)\nif err != nil { /* port taken; fail fast before starting RPC */ }","typeGuard":null,"tryCatchPattern":"if cause := context.Cause(ctx); cause != nil && strings.HasPrefix(cause.Error(), \"prommetrics \") {\n    log.Error(\"metrics server failure shut down process\", \"cause\", cause)\n}","preventionTips":["Pre-bind the prometheus port at startup to fail fast with a clear error","Assign unique metrics ports per RPC service on the same host","Skip the metrics cancel path when prometheus is disabled or optional"],"tags":["prometheus","metrics","context-cancel"],"backgroundTag":"metrics-server-exited","analyzedSha":"175a7bb0673eca18e9d1b10bff4f728da6b1b513","analyzedAt":"2026-09-04T16:52:56.821Z","contentChangedAt":"2026-09-04T16:52:56.821Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}