apache/beam · critical
type already registered for
Error message
type already registered for %v, and new type %v != %v (existing type)
What it means
This panic fires in RegisterType when two different Go types map to the same TypeKey. The Apache Beam Go SDK keeps a global registry mapping string type keys to reflect.Type values; if a key computed for a new type is already present but bound to a different type, the registry would be corrupted, so the SDK panics. It signals a genuine type-identity collision, not a user-facing error return.
Solutions
- Check which two types collide: the panic message shows the key, the new type, and the existing type; align the registrations so only one type is registered per key.
- Remove duplicate beam.RegisterType / RegisterDoFn / RegisterCoder calls for the colliding type (often in init functions of copied or vendored packages).
- If a custom type key is being generated, make it unique (include the full package path and any generic parameters).
- Restructure code so distinct types are not name-identical across vendor copies; consolidate duplicated package copies.
Example fix
// before
// package a: type Event struct{}
// package b (vendored copy): type Event struct{}
beam.RegisterType(reflect.TypeOf(a.Event{}))
beam.RegisterType(reflect.TypeOf(b.Event{})) // panics: same key, different type
// after
// keep a single canonical definition of Event and register it once
beam.RegisterType(reflect.TypeOf(a.Event{})) Defensive patterns
Strategy: validation
Validate before calling
k := beam.TypeKey(reflect.TypeOf(myType{}))
if _, exists := registryCheck(k); exists { /* skip duplicate registration or ensure identical type */ } Prevention
- Register each type exactly once, ideally in the package that defines it via init().
- Avoid vendoring duplicate copies of packages that call beam.RegisterType.
- Make custom type keys include the full package path and generic parameters.
When it happens
Trigger: Calling beam.RegisterType (directly or via RegisterDoFn/RegisterCoder) with a type whose TypeKey (type name incl. package path, plus generic type arguments) collides with an already-registered but distinct type; e.g. registering two different types that produce the same key, or registering a type in a package that gets re-loaded under an identical key.
Common situations: Duplicate registrations across packages with identical type names in different vendored copies; custom TypeKey/Encoders registered twice with differing types; build-tag or plugin setups that load the same package twice under one binary; renaming a struct while stale generated init code still registers the old one.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- scheme already registered
- AfterProcessingTime trigger set without a delay or…
- At least one subtrigger required for composite triggers.
- attempted to add namespace to missing coder id
- attempted to add namespace to missing windowing strategy id
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/1d72d503c149cfd1.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/types.go:43
var types = make(map[string]reflect.Type)
// RegisterType inserts "external" types into a global type registry to bypass
// serialization and preserve full method information. It should be called in
// init() only. Returns the external key for the type.
func RegisterType(t reflect.Type) string {
if initialized {
panic("Init hooks have already run. Register type during init() instead.")
}
t = reflectx.SkipPtr(t)
k, ok := TypeKey(t)
if !ok {
panic(fmt.Sprintf("invalid registration type: %v", t))
}
if v, exists := types[k]; exists && v != t {
panic(fmt.Sprintf("type already registered for %v, and new type %v != %v (existing type)", k, t, v))
}
types[k] = t
return k
}
// LookupType looks up a type in the global type registry by external key.
func LookupType(key string) (reflect.Type, bool) {
t, ok := types[key]
return t, ok
}
// TypeKey returns the external key of a given type. Returns false if not a
// candidate for registration.
func TypeKey(t reflect.Type) (string, bool) {
if t.PkgPath() == "" || t.Name() == "" {
return "", false // no pre-declared or unnamed types
}
return fmt.Sprintf("%v.%v", t.PkgPath(), t.Name()), trueView on GitHub (pinned to 12126d8942)