{"record":{"id":"e7a1c6d8907fb275","repo":"openimsdk/open-im-server","slug":"rpc-s-w","errorCode":null,"errorMessage":"rpc %s %w","messagePattern":"rpc (.+?) %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/common/startrpc/start.go","lineNumber":255,"sourceCode":"\t\tlog.ZDebug(ctx, \"rpc start register\", \"rpcRegisterName\", rpcRegisterName, \"registerIP\", registerIP, \"rpcPort\", rpcPort)\n\t\tgrpcOpt := grpc.WithTransportCredentials(insecure.NewCredentials())\n\t\trpcGracefulStop = make(chan struct{})\n\t\tgo func() {\n\t\t\t<-ctx.Done()\n\t\t\trpcServer.GracefulStop()\n\t\t\tclose(rpcGracefulStop)\n\t\t}()\n\t\tif err := client.Register(ctx, rpcRegisterName, registerIP, rpcListener.Addr().(*net.TCPAddr).Port, grpcOpt); err != nil {\n\t\t\tcancel(fmt.Errorf(\"rpc register %s %w\", rpcRegisterName, err))\n\t\t\treturn\n\t\t}\n\n\t\tgo func() {\n\t\t\terr := rpcServer.Serve(rpcListener)\n\t\t\tif err == nil {\n\t\t\t\terr = fmt.Errorf(\"serve end\")\n\t\t\t}\n\t\t\tcancel(fmt.Errorf(\"rpc %s %w\", rpcRegisterName, err))\n\t\t}()\n\t}\n\n\terr = rpcFn(ctx, config, client, &grpcServiceRegistrar{onRegisterService: onGrpcServiceRegistrar})\n\tif err != nil {\n\t\treturn err\n\t}\n\t<-ctx.Done()\n\tlog.ZDebug(ctx, \"cmd wait done\", \"err\", context.Cause(ctx))\n\tif rpcGracefulStop != nil {\n\t\ttimeout := time.NewTimer(time.Second * 15)\n\t\tdefer timeout.Stop()\n\t\tselect {\n\t\tcase <-timeout.C:\n\t\t\tlog.ZWarn(ctx, \"rcp graceful stop timeout\", nil)\n\t\tcase <-rpcGracefulStop:\n\t\t\tlog.ZDebug(ctx, \"rcp graceful stop done\")\n\t\t}","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/openimsdk/open-im-server/blob/175a7bb0673eca18e9d1b10bff4f728da6b1b513/pkg/common/startrpc/start.go#L237-L273","documentation":"Wraps the error returned by rpcFn — the whole RPC startup/serve sequence — as 'rpc <name> <cause>'. This is the outermost wrapper you see when the gRPC server for a given service exits with any error (including the synthesized 'serve end').","triggerScenarios":"rpcFn returns non-nil after the Serve goroutine cancels the context, propagating the underlying cause (listen failure, register failure, or serve end).","commonSituations":"Any of the earlier failures (port bind, registration, unexpected serve exit) surfacing at the top level; often seen in process logs as the fatal startup error line.","solutions":["Read the wrapped %w cause at the end of the message to find the root failure","Fix the root cause (port conflict, registry connectivity, config)","Check that only one instance per rpcRegisterName/port is running"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := startrpc.Start(ctx, cfg); err != nil {\n    log.Fatalf(\"rpc startup failed: %v\", err) // %w chain reveals root cause\n}","preventionTips":["Always unwrap errors (%w / errors.Unwrap) before diagnosing","Log the full error chain, not just the top wrapper","Run one binary instance per register name/port"],"tags":["grpc","startup","lifecycle"],"backgroundTag":"rpc-startup-failed","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"}