{"record":{"id":"bb83f3fa922c28fe","repo":"temporalio/temporal","slug":"component-type-s-must-be-struct-or-pointer-to-str","errorCode":null,"errorMessage":"component type %s must be struct or pointer to struct","messagePattern":"component type (.+?) must be struct or pointer to struct","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"chasm/registry.go","lineNumber":273,"sourceCode":"\tif existingComponent, ok := r.rcByID[id]; ok {\n\t\treturn fmt.Errorf(\"component ID %d collision between %s and %s\", id, fqn, existingComponent.fqType())\n\t}\n\n\tfor key, value := range rc.contextValues {\n\t\tif existingValue, ok := r.rcContextValues[key]; ok {\n\t\t\treturn fmt.Errorf(\"context value key %v registered by component %s conflicts with component %s\", key, fqn, existingValue.fqn)\n\t\t}\n\t\tr.rcContextValues[key] = valueWithFqn{\n\t\t\tv:   value,\n\t\t\tfqn: fqn,\n\t\t}\n\t}\n\n\t// rc.goType implements Component interface; therefore, it must be a struct.\n\t// This check to protect against the interface itself being registered.\n\tif !(rc.goType.Kind() == reflect.Struct ||\n\t\t(rc.goType.Kind() == reflect.Pointer && rc.goType.Elem().Kind() == reflect.Struct)) {\n\t\treturn fmt.Errorf(\"component type %s must be struct or pointer to struct\", rc.goType.String())\n\t}\n\tif _, ok := r.rcByGoType[rc.goType]; ok {\n\t\treturn fmt.Errorf(\"component type %s is already registered\", rc.goType.String())\n\t}\n\tr.warnUnmanagedFields(fqn, rc)\n\n\tr.rcByFqn[fqn] = rc\n\tr.rcByID[id] = rc\n\tr.rcByGoType[rc.goType] = rc\n\treturn nil\n}\n\nfunc (r *Registry) validate(rc *RegistrableComponent) error {\n\tif err := r.validateName(rc.componentType); err != nil {\n\t\treturn err\n\t}\n\treturn r.validateVisibilityBusinessIDAlias(rc)\n}","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/chasm/registry.go#L255-L291","documentation":"chasm.Registry.registerComponent rejects component implementations whose reflect.Type is not a struct or a pointer to a struct. The Component interface is backed by Go structs, so registering the interface type itself or any other kind (map, slice, int, etc.) cannot be managed by the framework. This guard exists to prevent accidentally registering the interface type when the intent was a concrete implementation.","triggerScenarios":"Calling chasm.Register (which calls registerComponent) with a generic parameter that is an interface type, e.g. Register[SomeComponent](...), or a non-struct type such as a named map/slice/func type.","commonSituations":"Developer passes the interface name instead of the concrete struct; refactor renamed a struct into an interface; copy-pasted registration code where the type parameter was swapped; registering a type alias pointing to a non-struct kind.","solutions":["Register the concrete struct type: chasm.Register[MyComponentImpl](registry, ...).","If *MyComponentImpl is used elsewhere, either kind works — but never the interface type.","Print reflect.TypeOf to confirm the registered type is a struct or *struct."],"exampleFix":"// before\nchasm.Register[OrderComponent](reg, opts)\n// after\nchasm.Register[OrderComponentImpl](reg, opts)","handlingStrategy":"validation","validationCode":"t := reflect.TypeOf((*MyComponent)(nil)).Elem()\nif t.Kind() == reflect.Interface ||\n\t!(t.Kind() == reflect.Struct || (t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Struct)) {\n\treturn fmt.Errorf(\"%s must be struct or pointer to struct\", t)\n}","typeGuard":"func isStructOrStructPtr(t reflect.Type) bool {\n\treturn t != nil && (t.Kind() == reflect.Struct || (t.Kind() == reflect.Pointer && t.Elem().Kind() == reflect.Struct))\n}","tryCatchPattern":null,"preventionTips":["Always pass the concrete struct type, never the interface, as the type parameter to chasm.Register.","Add a compile-time check: var _ chasm.Component = (*MyComponentImpl)(nil).","Register components in a single package-level init per service."],"tags":["chasm","registry","go-reflect","component-registration"],"backgroundTag":"invalid-registered-type-kind","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}