{"record":{"id":"897021c675649e1f","repo":"apache/beam","slug":"registerprofcapturehook-s-registered-twice","errorCode":null,"errorMessage":"RegisterProfCaptureHook: %s registered twice","messagePattern":"RegisterProfCaptureHook: (.+?) registered twice","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/x/hooks/perf/perf.go","lineNumber":141,"sourceCode":"\t\t\t\t\tname, opts := hooks.Decode(h)\n\t\t\t\t\tif err := heapCaptureHookRegistry[name](opts)(ctx, fmt.Sprintf(\"heap%s\", req.InstructionId), &heapProfBuf); err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\theapProfBuf.Reset()\n\t\t\t\treturn nil\n\t\t\t},\n\t\t}\n\t}\n\thooks.RegisterHook(\"heap\", hf)\n}\n\n// RegisterProfCaptureHook registers a CaptureHookFactory for the\n// supplied identifier. It panics if the same identifier is\n// registered twice.\nfunc RegisterProfCaptureHook(name string, c CaptureHookFactory) {\n\tif _, exists := profCaptureHookRegistry[name]; exists {\n\t\tpanic(fmt.Sprintf(\"RegisterProfCaptureHook: %s registered twice\", name))\n\t}\n\tprofCaptureHookRegistry[name] = c\n}\n\n// EnableProfCaptureHook actives a registered profile capture hook for a given pipeline.\nfunc EnableProfCaptureHook(name string, opts ...string) {\n\t_, exists := profCaptureHookRegistry[name]\n\tif !exists {\n\t\tpanic(fmt.Sprintf(\"EnableProfCaptureHook: %s not registered\", name))\n\t}\n\n\tenc := hooks.Encode(name, opts)\n\n\tfor i, h := range enabledProfCaptureHooks {\n\t\tn, _ := hooks.Decode(h)\n\t\tif h == n {\n\t\t\t// Rewrite the registration with the current arguments\n\t\t\tenabledProfCaptureHooks[i] = enc","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/x/hooks/perf/perf.go#L123-L159","documentation":"RegisterProfCaptureHook stores a CPU-profile CaptureHookFactory in a package-level registry keyed by name, and deliberately panics on duplicate registration. Because hooks are typically registered from package init functions, this fires at process startup when two packages (or two copies of the same package via different module versions) register the same hook identifier.","triggerScenarios":"Calling perf.RegisterProfCaptureHook(name, factory) with a name already present in profCaptureHookRegistry — typically two init() functions in the dependency graph registering the same identifier, or an app registering a hook that a vendored package also registers.","commonSituations":"Importing two Beam x/hooks packages that both register the same profiler name; accidental double registration in test setup plus production init; Go module upgrades pulling two versions of a hook package that both run init.","solutions":["Find the duplicate registration call sites (grep for RegisterProfCaptureHook with the offending name) and remove one.","Register the hook only once — prefer package init in a single package, not both init and main.","If two module versions of a hook package are linked, deduplicate the dependency (go mod tidy / go mod graph) so only one init runs.","If dynamic registration is needed, guard with a check against the registry or track registration state before calling."],"exampleFix":"// before\nperf.RegisterProfCaptureHook(\"myprof\", myFactory) // called in both init() and main\n// after\nvar profOnce sync.Once\nfunc ensureProfHook() {\n    profOnce.Do(func() { perf.RegisterProfCaptureHook(\"myprof\", myFactory) })\n}","handlingStrategy":"validation","validationCode":"// guard before registering\nif _, exists := perfRegistrySnapshot[\"myprof\"]; !exists {\n    perf.RegisterProfCaptureHook(\"myprof\", myFactory)\n}","typeGuard":null,"tryCatchPattern":"func() (ok bool) {\n    defer func() {\n        if r := recover(); r != nil {\n            log.Printf(\"hook already registered: %v\", r)\n            ok = true\n        }\n    }()\n    perf.RegisterProfCaptureHook(\"myprof\", myFactory)\n    return true\n}()","preventionTips":["Register each hook exactly once, in a single package init.","Never register hooks from both init() and application main/test setup.","Keep the hook package to a single module version in go.mod.","Use sync.Once for any conditional registration path."],"tags":["go","apache-beam","initialization","duplicate-registration"],"backgroundTag":"module-init-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}