{"record":{"id":"479db05b2265abfe","repo":"grpc/grpc-go","slug":"profiling-may-be-initialized-at-most-once","errorCode":null,"errorMessage":"profiling may be initialized at most once","messagePattern":"profiling may be initialized at most once","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/profiling/profiling.go","lineNumber":202,"sourceCode":"\tstat.mu.Unlock()\n}\n\n// statsInitialized is 0 before InitStats has been called. Changed to 1 by\n// exactly one call to InitStats.\nvar statsInitialized int32\n\n// Stats for the last defaultStreamStatsBufsize RPCs will be stored in memory.\n// This can be configured by the registering server at profiling service\n// initialization with google.golang.org/grpc/profiling/service.ProfilingConfig\nconst defaultStreamStatsSize uint32 = 16 << 10\n\n// StreamStats is a CircularBuffer containing data from the last N RPC calls\n// served, where N is set by the user. This will contain both server stats and\n// client stats (but each stat will be tagged with whether it's a server or a\n// client in its Tags).\nvar StreamStats *buffer.CircularBuffer\n\nvar errAlreadyInitialized = errors.New(\"profiling may be initialized at most once\")\n\n// InitStats initializes all the relevant Stat objects. Must be called exactly\n// once per lifetime of a process; calls after the first one will return an\n// error.\nfunc InitStats(streamStatsSize uint32) error {\n\tvar err error\n\tif !atomic.CompareAndSwapInt32(&statsInitialized, 0, 1) {\n\t\treturn errAlreadyInitialized\n\t}\n\n\tif streamStatsSize == 0 {\n\t\tstreamStatsSize = defaultStreamStatsSize\n\t}\n\n\tStreamStats, err = buffer.NewCircularBuffer(streamStatsSize)\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/profiling/profiling.go#L184-L220","documentation":"Returned by profiling.InitStats when it has already been called once. InitStats uses an atomic CompareAndSwap on statsInitialized (0->1) to enforce single initialization; a second call finds it already 1 and returns errAlreadyInitialized. This is by design—profiling's StreamStats CircularBuffer is process-global and must be set up exactly once.","triggerScenarios":"Calling profiling.InitStats (or profiling/service RegisterProfiling which calls InitStats internally) more than once in the same process. Common in tests that start multiple profiling services, or in long-running servers that reinitialize profiling.","commonSituations":"Test suites that call InitStats in setup without teardown; multiple gRPC servers in one binary each trying to register the profiling service; hot-reload or restart logic that re-runs initialization code.","solutions":["Call profiling.InitStats exactly once per process lifecycle, typically at startup.","In tests, guard re-initialization with a sync.Once or reset statsInitialized via test helpers if available.","If using profiling/service.RegisterProfiling, ensure it is only called once across all servers in the binary.","Check IsEnabled and whether StreamStats is already non-nil before calling InitStats."],"exampleFix":"// before: may call InitStats multiple times\nfunc setupProfiling(size uint32) error {\n    return profiling.InitStats(size)\n}\n// after: guard with sync.Once\nvar initOnce sync.Once\nvar initErr error\nfunc setupProfiling(size uint32) error {\n    initOnce.Do(func() { initErr = profiling.InitStats(size) })\n    return initErr\n}","handlingStrategy":"validation","validationCode":"// Guard InitStats with sync.Once to prevent double initialization.\nvar profilingOnce sync.Once\nvar profilingInitErr error\nfunc safeInitStats(size uint32) error {\n    profilingOnce.Do(func() { profilingInitErr = profiling.InitStats(size) })\n    return profilingInitErr\n}","typeGuard":null,"tryCatchPattern":"err := profiling.InitStats(size)\nif err != nil && strings.Contains(err.Error(), \"at most once\") {\n    // already initialized; safe to ignore\n    return nil\n}","preventionTips":["Call profiling.InitStats exactly once at process startup.","Guard initialization with sync.Once in shared setup code.","In tests, reset state or skip re-initialization for the profiling service.","Check profiling.IsEnabled() or StreamStats != nil before initializing."],"tags":["profiling","initialization","validation","internal","grpc"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}