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

  1. Make encode have signature func(T) []byte and decode func([]byte) T exactly matching t
  2. Test the registration early (a unit test or build-time check) since it panics in init
  3. Read the wrapped underlying error to see which validation failed
  4. 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

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


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)