{"record":{"id":"b19c398e0bf54e0e","repo":"temporalio/temporal","slug":"errduplicateregistration","errorCode":"ErrDuplicateRegistration","errorMessage":"%w: command handler for %v: %v","messagePattern":"%w: command handler for (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"chasm/lib/workflow/registry.go","lineNumber":47,"sourceCode":"}\n\n// NewRegistry creates a new [Registry].\nfunc NewRegistry() *Registry {\n\treturn &Registry{\n\t\tcommandHandlers:          make(map[enumspb.CommandType]CommandHandler),\n\t\teventDefinitions:         make(map[enumspb.EventType]EventDefinition),\n\t\teventDefinitionsByGoType: make(map[reflect.Type]EventDefinition),\n\t}\n}\n\n// Register registers all command handlers and event definitions from a [Library].\n// Returns an [ErrDuplicateRegistration] if a handler or definition is already registered.\n// All registration is expected to happen in a single thread on process initialization.\nfunc (r *Registry) Register(lib Library) error {\n\tfor t, handler := range lib.CommandHandlers() {\n\t\tif existing, ok := r.commandHandlers[t]; ok {\n\t\t\treturn fmt.Errorf(\"%w: command handler for %v: %v\", ErrDuplicateRegistration, t, existing)\n\t\t}\n\t\tr.commandHandlers[t] = handler\n\t}\n\tfor _, def := range lib.EventDefinitions() {\n\t\tif existing, ok := r.eventDefinitions[def.Type()]; ok {\n\t\t\treturn fmt.Errorf(\"%w: event handler for %v: %v\", ErrDuplicateRegistration, def.Type(), existing)\n\t\t}\n\t\tgoType := reflect.TypeOf(def)\n\t\tfor goType.Kind() == reflect.Pointer {\n\t\t\tgoType = goType.Elem()\n\t\t}\n\t\tif existing, ok := r.eventDefinitionsByGoType[goType]; ok {\n\t\t\treturn fmt.Errorf(\"%w: event definition for Go type %v: %v\", ErrDuplicateRegistration, goType, existing)\n\t\t}\n\t\tr.eventDefinitions[def.Type()] = def\n\t\tr.eventDefinitionsByGoType[goType] = def\n\t}\n\treturn nil\n}","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/chasm/lib/workflow/registry.go#L29-L65","documentation":"The CHASM workflow Registry.Register rejects a Library whose command handler map contains a command type already registered by a previously registered library. The error wraps ErrDuplicateRegistration and names the conflicting command type plus the existing handler. Registration is expected to happen once, single-threaded, at process init.","triggerScenarios":"Calling Registry.Register(lib) where lib.CommandHandlers() returns a handler for a command type t that r.commandHandlers already holds — typically by registering two libraries that both define handlers for the same command type, or re-registering the same library twice.","commonSituations":"Two plugins/libraries bundled into the same binary both register the same command type; an init() or registration path runs twice (e.g. library imported in two places, or Register called in both init and main); copy-pasted library code kept the same command type.","solutions":["Find the duplicate: the message names the command type and existing handler — locate both libraries registering it","Remove one registration or consolidate the two command handlers into a single library","Guard registration with a sync.Once or check-and-skip so init paths that may run twice register only once","If intentional replacement is needed, create a fresh Registry instead of reusing one (no overwrite API exists)"],"exampleFix":"// before\nregistry.Register(libA) // registers command type Foo\nregistry.Register(libB) // also registers command type Foo -> duplicate\n// after\nregistry.Register(libA)\nregistry.Register(libBWithoutFoo) // libB no longer defines Foo handler","handlingStrategy":"validation","validationCode":"// Guard against double registration before calling Register\nvar once sync.Once\nfunc registerOnce(r *chasmworkflow.Registry, lib Library) {\n    once.Do(func() { _ = r.Register(lib) })\n}","typeGuard":null,"tryCatchPattern":"// Go\nif err := registry.Register(lib); err != nil {\n    if errors.Is(err, ErrDuplicateRegistration) {\n        logger.Warn(\"library already registered; skipping\", \"err\", err)\n        return nil\n    }\n    return err\n}","preventionTips":["Register all libraries exactly once at process init, single-threaded","Keep a central registration function; never call Register from library init()s","Audit bundled libraries for overlapping command types before adding a new one","On duplicate, treat it as a build/packaging error, not a runtime retry case"],"tags":["chasm","workflow","registry","registration"],"backgroundTag":"duplicate-registration","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}