temporalio/temporal · error
component type %s must be and interface or struct that imple
Error message
component type %s must be and interface or struct that implements Component interface
What it means
registerTask validates that the task's associated component type is either an interface, or a struct/pointer-to-struct that is AssignableTo the Component interface. A task must declare which component it operates on; if the declared type doesn't satisfy Component, the task cannot be dispatched. This is typically a wrong type parameter in RegisterTask.
Source
Thrown at chasm/registry.go:325
return fmt.Errorf("task %s is already registered", fqn)
}
if existingTask, ok := r.rtByID[id]; ok {
return fmt.Errorf("task type ID %d collision between %s and %s", id, fqn, existingTask.fqType())
}
if !(rt.goType.Kind() == reflect.Struct ||
(rt.goType.Kind() == reflect.Pointer && rt.goType.Elem().Kind() == reflect.Struct)) {
return fmt.Errorf("task type %s must be struct or pointer to struct", rt.goType.String())
}
if _, ok := r.rtByGoType[rt.goType]; ok {
return fmt.Errorf("task type %s is already registered", rt.goType.String())
}
if !(rt.componentGoType.Kind() == reflect.Interface ||
(rt.componentGoType.Kind() == reflect.Struct ||
(rt.componentGoType.Kind() == reflect.Pointer && rt.componentGoType.Elem().Kind() == reflect.Struct)) &&
rt.componentGoType.AssignableTo(reflect.TypeFor[Component]())) {
return fmt.Errorf("component type %s must be and interface or struct that implements Component interface", rt.componentGoType.String())
}
r.rtByFqn[fqn] = rt
r.rtByID[id] = rt
r.rtByGoType[rt.goType] = rt
return nil
}
func (r *Registry) validateName(n string) error {
if n == "" {
return errors.New("name must not be empty")
}
if !nameValidator.MatchString(n) {
return fmt.Errorf("name %s is invalid. name must follow golang identifier rules: %s", n, nameValidator.String())
}
return nil
}
View on GitHub (pinned to bde624efd1)
Solutions
- Make the component type parameter a type that implements chasm.Component (verify required methods exist).
- Swap type parameters if Task and Component were reversed at the call site.
- Add a compile-time assertion `var _ chasm.Component = (*MyComponent)(nil)` to catch drift early.
Example fix
// before var _ chasm.Component = (*OrderDTO)(nil) // fails chasm.RegisterTask[OrderTask, OrderDTO](reg, "order_task", opts) // after var _ chasm.Component = (*OrderImpl)(nil) chasm.RegisterTask[OrderTask, OrderImpl](reg, "order_task", opts)
Defensive patterns
Strategy: type-guard
Validate before calling
var _ chasm.Component = (*MyComponent)(nil) // compile-time guard before registration
Type guard
func implementsComponent(t reflect.Type) bool {
return t != nil && t.AssignableTo(reflect.TypeFor[chasm.Component]())
} Prevention
- Add compile-time assertions (var _ chasm.Component = (*T)(nil)) next to every component struct.
- Keep type-parameter order consistent: RegisterTask[TaskType, ComponentType].
- After chasm upgrades, build first — interface method changes surface at compile time.
When it happens
Trigger: Passing a component type parameter that does not implement chasm.Component (missing required methods, or a totally unrelated struct/pointer type) to chasm.RegisterTask.
Common situations: Component interface evolved and the type no longer satisfies it after an upgrade; passing a DTO struct instead of the component; mixing up type-parameter order in RegisterTask[Task, Component].
Related errors
- task %s is already registered
- task type ID %d collision between %s and %s
- task type %s must be struct or pointer to struct
- task type %s is already registered
- ErrDuplicateRegistration
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/a08d2765a2e0d44c.
Report an issue: GitHub.