{"record":{"id":"50aac765dc353ade","repo":"temporalio/temporal","slug":"task-type-s-is-already-registered","errorCode":null,"errorMessage":"task type %s is already registered","messagePattern":"task type (.+?) is already registered","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"chasm/registry.go","lineNumber":319,"sourceCode":"\tfqn, id, err := rt.registerToLibrary(lib)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif _, ok := r.rtByFqn[fqn]; ok {\n\t\treturn fmt.Errorf(\"task %s is already registered\", fqn)\n\t}\n\n\tif existingTask, ok := r.rtByID[id]; ok {\n\t\treturn fmt.Errorf(\"task type ID %d collision between %s and %s\", id, fqn, existingTask.fqType())\n\t}\n\n\tif !(rt.goType.Kind() == reflect.Struct ||\n\t\t(rt.goType.Kind() == reflect.Pointer && rt.goType.Elem().Kind() == reflect.Struct)) {\n\t\treturn fmt.Errorf(\"task type %s must be struct or pointer to struct\", rt.goType.String())\n\t}\n\tif _, ok := r.rtByGoType[rt.goType]; ok {\n\t\treturn fmt.Errorf(\"task type %s is already registered\", rt.goType.String())\n\t}\n\tif !(rt.componentGoType.Kind() == reflect.Interface ||\n\t\t(rt.componentGoType.Kind() == reflect.Struct ||\n\t\t\t(rt.componentGoType.Kind() == reflect.Pointer && rt.componentGoType.Elem().Kind() == reflect.Struct)) &&\n\t\t\trt.componentGoType.AssignableTo(reflect.TypeFor[Component]())) {\n\t\treturn fmt.Errorf(\"component type %s must be and interface or struct that implements Component interface\", rt.componentGoType.String())\n\t}\n\n\tr.rtByFqn[fqn] = rt\n\tr.rtByID[id] = rt\n\tr.rtByGoType[rt.goType] = rt\n\treturn nil\n}\n\nfunc (r *Registry) validateName(n string) error {\n\tif n == \"\" {\n\t\treturn errors.New(\"name must not be empty\")\n\t}","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/chasm/registry.go#L301-L337","documentation":"registerTask found that r.rtByGoType already contains a task with this exact Go type — the same task implementation was registered twice. The registry allows only one registration per Go type regardless of the name used.","triggerScenarios":"Calling chasm.RegisterTask twice with the same task Go type (even with different names/options); duplicate init() paths registering the same task; test setup re-registering tasks on a shared registry.","commonSituations":"Task registered in both a library's init and the application's bootstrap; re-running a bootstrap function during tests; accidental duplicated registration line after a merge.","solutions":["Delete the second registration of the same task Go type.","Centralize task registration in one init/bootstrap function.","Use a fresh Registry instance for isolated test cases instead of re-registering into a shared one."],"exampleFix":"// before\nchasm.RegisterTask[EmailTask, OrderImpl](reg, \"email\", opts)\nchasm.RegisterTask[EmailTask, OrderImpl](reg, \"email2\", opts)\n// after\nchasm.RegisterTask[EmailTask, OrderImpl](reg, \"email\", opts)","handlingStrategy":"validation","validationCode":"if _, ok := registryLookupTask(reflect.TypeOf(MyTask{})); ok {\n\treturn errors.New(\"task already registered; skip duplicate RegisterTask call\")\n}","typeGuard":null,"tryCatchPattern":"if err := chasm.RegisterTask[MyTask, C](reg, name, opts); err != nil && strings.Contains(err.Error(), \"is already registered\") {\n\treturn nil\n}","preventionTips":["Single central init/bootstrap for all task registrations.","Avoid registering tasks in both library and application packages.","Use fresh Registries per test case to isolate registration state."],"tags":["chasm","registry","duplicate-registration","task-registration"],"backgroundTag":"duplicate-task-registration","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}