{"record":{"id":"da83bc69ffae7dd3","repo":"apache/beam","slug":"runner-v-already-defined","errorCode":null,"errorMessage":"runner %v already defined","messagePattern":"runner (.+?) already defined","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/runner.go","lineNumber":33,"sourceCode":"\npackage beam\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/apache/beam/sdks/v2/go/pkg/beam/log\"\n)\n\nvar (\n\trunners = make(map[string]func(ctx context.Context, p *Pipeline) (PipelineResult, error))\n)\n\n// RegisterRunner associates the name with the supplied runner, making it available\n// to execute a pipeline via Run.\nfunc RegisterRunner(name string, fn func(ctx context.Context, p *Pipeline) (PipelineResult, error)) {\n\tif _, ok := runners[name]; ok {\n\t\tpanic(fmt.Sprintf(\"runner %v already defined\", name))\n\t}\n\trunners[name] = fn\n}\n\n// Run executes the pipeline using the selected registred runner. It is customary\n// to define a \"runner\" with no default as a flag to let users control runner\n// selection.\nfunc Run(ctx context.Context, runner string, p *Pipeline) (PipelineResult, error) {\n\tfn, ok := runners[runner]\n\tif !ok {\n\t\tlog.Exitf(ctx, \"Runner %v not registered. Forgot to _ import it?\", runner)\n\t}\n\treturn fn(ctx, p)\n}\n","sourceCodeStart":15,"sourceCodeEnd":48,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/runner.go#L15-L48","documentation":"RegisterRunner panics when asked to register a runner name that is already present in the global runner registry. Runners are registered once at package init time, so a duplicate name indicates two registrations of the same runner identifier.","triggerScenarios":"Calling beam.RegisterRunner(\"x\", fn) twice, or two packages' init() functions both registering the same runner name (including re-registering a built-in like \"direct\" or \"dataflow\").","commonSituations":"Importing a custom runner package plus manually registering the same name, or copy-pasted init code in test files that registers the standard runner again.","solutions":["Remove the duplicate RegisterRunner call","Use a unique runner name for your custom runner","Guard registration with a check of an exported map or a sync.Once before calling RegisterRunner","If intentionally overriding, fork the registry instead of re-registering the built-in name"],"exampleFix":"// before\nfunc init() { beam.RegisterRunner(\"direct\", myFn) } // panics: already defined\n// after\nfunc init() { beam.RegisterRunner(\"mydirect\", myFn) }","handlingStrategy":"validation","validationCode":"if _, ok := beam.Runners()[name]; ok {\n    return // already registered\n}\nbeam.RegisterRunner(name, fn)","typeGuard":null,"tryCatchPattern":"// Go panics are not recoverable by type; use defer/recover at init boundary if needed\nfunc safeRegister(name string, fn RunnerFn) {\n    defer func() { _ = recover() }()\n    beam.RegisterRunner(name, fn)\n}","preventionTips":["Register each runner name exactly once, ideally in a single package","Use unique names like org-runner-name for custom runners","Never re-register built-in runner names","Keep init() registration in one file per runner"],"tags":["go","registration","init"],"backgroundTag":"file-already-exists","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"}