apache/beam · critical
RegisterCoder failed for type
Error message
RegisterCoder failed for type %v
What it means
RegisterCoder validates the encoder/decoder pair by constructing a CustomCoder and panics wrapping the error as "RegisterCoder failed for type %v" if construction fails. Because registration typically happens in init(), this panic crashes the program at startup. It means the supplied enc/dec functions do not satisfy the validators' signature requirements for the type.
Solutions
- Make encode have signature func(T) []byte and decode func([]byte) T exactly matching t
- Test the registration early (a unit test or build-time check) since it panics in init
- Read the wrapped underlying error to see which validation failed
- Check for validator/signature changes after Beam upgrades
Example fix
// before
coder.RegisterCoder(reflect.TypeOf(MyType{}), func(m MyType) ([]byte, error) { ... }, ...)
// after
coder.RegisterCoder(reflect.TypeOf(MyType{}),
func(m MyType) []byte { return encodeMyType(m) },
func(b []byte) MyType { return decodeMyType(b) }) Defensive patterns
Strategy: validation
Validate before calling
enc := func(v T) []byte { return encodeT(v) }
dec := func(b []byte) T { return decodeT(b) }
if _, err := coder.NewCustomCoder("check", reflect.TypeOf(T{}), enc, dec); err != nil {
panic(fmt.Sprintf("invalid coder funcs for T: %v", err))
} Type guard
func validCoderFuncs(t reflect.Type, enc, dec any) bool {
_, err := coder.NewCustomCoder("check", t, enc, dec)
return err == nil
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Fatalf("coder registration failed at startup: %v", r)
}
}() Prevention
- Register coders with exact func(T) []byte / func([]byte) T signatures
- Smoke-test init() registrations in CI before deployment
- Re-check registrations after any type refactor or Beam upgrade
When it happens
Trigger: Calling coder.RegisterCoder(t, enc, dec) with enc/dec whose signatures fail validateEncoder/validateDecoder — wrong parameter or return types, non-function values, or wrong arity.
Common situations: Registration in package init() with hand-written funcs whose types drifted after a refactor; copying a registration for a different type without updating the signatures; passing methods instead of matching plain funcs.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Creating CustomCoder for type failed
- couldn't decode characteristic for variant
- empty slice passed as an argument to trigger.AfterAny()
- err
- error decoding append bag user state window key
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/ac051e6bf693c086.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/graph/coder/registry.go:49
// RegisterCoder registers a user defined coder for a given type, and will
// be used if there is no beam coder for that type. Must be called prior to beam.Init(),
// preferably in an init() function.
//
// Coders are encoder and decoder pairs, and operate around []bytes.
//
// The coder used for a given type follows this ordering:
// 1. Coders for Known Beam types.
// 2. Coders registered for specific types
// 3. Coders registered for interfaces types
// 4. Default coder (JSON)
//
// Types of kind Interface, are handled specially by the registry, so they may be iterated
// over to check if element types implement them.
//
// Repeated registrations of the same type overrides prior ones.
func RegisterCoder(t reflect.Type, enc, dec any) {
if _, err := NewCustomCoder(t.String(), t, enc, dec); err != nil {
panic(errors.Wrapf(err, "RegisterCoder failed for type %v", t))
}
if t.Kind() == reflect.Interface {
// If it's already in the registry, then it's already in the list
// and should be removed.
if _, ok := coderRegistry[t]; ok {
var index int
for i, iT := range interfaceOrdering {
if iT == t {
index = i
break
}
}
interfaceOrdering = append(interfaceOrdering[:index], interfaceOrdering[index+1:]...)
}
// Either way, always append.
interfaceOrdering = append(interfaceOrdering, t)
}View on GitHub (pinned to 12126d8942)