{"record":{"id":"318d6d9236dc056d","repo":"apache/beam","slug":"init-hooks-have-already-run-register-type-during-init","errorCode":null,"errorMessage":"Init hooks have already run. Register type during init() instead.","messagePattern":"Init hooks have already run\\. Register type during init\\(\\) instead\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/runtime/types.go","lineNumber":32,"sourceCode":"// limitations under the License.\n\npackage runtime\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/apache/beam/sdks/v2/go/pkg/beam/core/util/reflectx\"\n)\n\nvar types = make(map[string]reflect.Type)\n\n// RegisterType inserts \"external\" types into a global type registry to bypass\n// serialization and preserve full method information. It should be called in\n// init() only. Returns the external key for the type.\nfunc RegisterType(t reflect.Type) string {\n\tif initialized {\n\t\tpanic(\"Init hooks have already run. Register type during init() instead.\")\n\t}\n\n\tt = reflectx.SkipPtr(t)\n\n\tk, ok := TypeKey(t)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"invalid registration type: %v\", t))\n\t}\n\n\tif v, exists := types[k]; exists && v != t {\n\t\tpanic(fmt.Sprintf(\"type already registered for %v, and new type %v != %v (existing type)\", k, t, v))\n\t}\n\ttypes[k] = t\n\treturn k\n}\n\n// LookupType looks up a type in the global type registry by external key.\nfunc LookupType(key string) (reflect.Type, bool) {","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/runtime/types.go#L14-L50","documentation":"runtime.RegisterType stores reflect.Type values in a global registry keyed by an external type key so serialized pipelines preserve full method info across process boundaries. Like the other registries it freezes once beam.Init() runs; late registration would make worker/driver registries inconsistent, so it panics.","triggerScenarios":"Calling runtime.RegisterType(t) (or wrappers RegisterDoFn/RegisterCoder/registerType that call it) after beam.Init() has executed, e.g. registering custom types/coders inside main post-Init or in tests after TestMain ran Init.","commonSituations":"Custom coder registration placed after beam.Init(); test files registering types lazily; plugin or module code whose init order relative to the main package's explicit beam.Init() call puts registration too late.","solutions":["Move all RegisterType calls into package init() functions.","Make sure beam.Init() runs only after all packages performing registration are imported.","For tests, rely on init()-time registration rather than per-test setup that runs after Init."],"exampleFix":"// before\nfunc main() {\n    beam.Init()\n    runtime.RegisterType(reflect.TypeOf(MyType{})) // panics\n}\n// after\nfunc init() {\n    runtime.RegisterType(reflect.TypeOf(MyType{}))\n}\nfunc main() {\n    beam.Init()\n}","handlingStrategy":"validation","validationCode":"// ensure call site is a package init() function:\nfunc init() { runtime.RegisterType(reflect.TypeOf(MyType{})) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Register types in init() functions of the package defining them","Ensure beam.Init() is called after all registering packages are imported","Do not register types from per-test setup after TestMain's Init"],"tags":["go","apache-beam","registration","reflection","panic"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}