{"record":{"id":"7292ec3ec5c4a5fe","repo":"temporalio/temporal","slug":"task-type-id-d-collision-between-s-and-s","errorCode":null,"errorMessage":"task type ID %d collision between %s and %s","messagePattern":"task type ID (.+?) collision between (.+?) and (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"chasm/registry.go","lineNumber":311,"sourceCode":"func (r *Registry) registerTask(\n\tlib namer,\n\trt *RegistrableTask,\n) error {\n\tif err := r.validateName(rt.taskType); err != nil {\n\t\treturn err\n\t}\n\n\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","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/chasm/registry.go#L293-L329","documentation":"Two different tasks hashed/derived the same numeric task type ID: r.rtByID already holds a task for this ID. IDs are derived from the task's FQN and are used as compact identifiers, so a collision means two tasks would be indistinguishable in encoded form. The error names both colliding FQNs.","triggerScenarios":"registering task A, then task B whose derived ID equals A's (ID derived from name); a version change that renamed one task so its ID now matches another.","commonSituations":"Large libraries where hash-derived IDs collide; renaming tasks during a refactor causing two names to map to one ID; registering tasks from multiple libraries that independently picked names producing the same ID.","solutions":["Rename one of the two conflicting task types so its derived ID changes.","Check the two FQNs in the message and pick a new, distinct name for the newer task.","If the ID space is shared across services, coordinate task naming conventions to avoid overlaps."],"exampleFix":"// before\nchasm.RegisterTask[T1, C](reg, \"order_close\", opts)\nchasm.RegisterTask[T2, C](reg, \"orderclose\", opts) // same derived ID\n// after\nchasm.RegisterTask[T1, C](reg, \"order_close\", opts)\nchasm.RegisterTask[T2, C](reg, \"order_close_v2\", opts)","handlingStrategy":"validation","validationCode":"// Maintain a set of assigned task type IDs at build/bootstrap time and fail fast on duplicates:\nif seenIDs[id] {\n\treturn fmt.Errorf(\"task type ID %d already used\", id)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Choose distinct, descriptive task names — ID is derived from the FQN.","Run a startup self-check/test that registers all tasks and asserts no collision.","Coordinate task naming across teams sharing one registry/library."],"tags":["chasm","registry","id-collision","task-registration"],"backgroundTag":"identifier-collision","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}