apache/beam · error
receiver type %v must be registered
Error message
receiver type %v must be registered
What it means
Thrown by encodeFn in Beam Go's graphx serializer when encoding a structural DoFn whose receiver type has no runtime.TypeKey or is not present in the runtime type registry (LookupType fails). Beam requires all serialized types to be pre-registered so the pipeline can be decoded on a worker; an unregistered receiver type would produce a graph the remote process cannot reconstruct.
Source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/serialize.go:248
}}, nil
case u.Fn != nil:
fn, err := encodeUserFn(u.Fn)
if err != nil {
wrapped := errors.Wrap(err, "bad userfn")
return nil, errors.WithContextf(wrapped, "encoding DoFn %v", u)
}
return &v1pb.Fn{Fn: fn}, nil
case u.Recv != nil:
t := reflect.TypeOf(u.Recv)
k, ok := runtime.TypeKey(reflectx.SkipPtr(t))
if !ok {
err := errors.Errorf("failed to create TypeKey for receiver type %T", u.Recv)
return nil, errors.WithContextf(err, "encoding structural DoFn %v", u)
}
if _, ok := runtime.LookupType(k); !ok {
err := errors.Errorf("receiver type %v must be registered", t)
return nil, errors.WithContextf(err, "encoding structural DoFn %v", u)
}
typ, err := encodeType(t)
if err != nil {
wrapped := errors.Wrapf(err, "failed to encode receiver type %T", u.Recv)
return nil, errors.WithContextf(wrapped, "encoding structural DoFn %v", u)
}
data, err := jsonx.Marshal(u.Recv)
if err != nil {
wrapped := errors.Wrapf(err, "failed to marshal receiver %v", u.Recv)
return nil, errors.WithContextf(wrapped, "encoding structural DoFn %v", u)
}
return &v1pb.Fn{Type: typ, Opt: string(data)}, nil
default:
return nil, errors.Errorf("failed to encode DoFn %v, missing fn", u)
}View on GitHub (pinned to 12126d8942)
Solutions
- Register the receiver type at package init with runtime.RegisterType(reflect.TypeOf(MyFn{})) (or call beam.RegisterFunction/registerDoFn helpers).
- Ensure the package containing the registration is imported by both the driver and the worker binary.
- Verify with runtime.TypeKey(reflectx.SkipPtr(reflect.TypeOf(fn))) and runtime.LookupType that the type resolves before building the pipeline.
- If the DoFn is genuinely dynamic/anonymous, switch to a named registered type or an emulated/serialized DoFn form.
Example fix
// before
func init() { /* no registration */ }
type myFn struct{}
// after
type myFn struct{}
func init() { runtime.RegisterType(reflect.TypeOf(myFn{})) } Defensive patterns
Strategy: validation
Validate before calling
k, ok := runtime.TypeKey(reflectx.SkipPtr(reflect.TypeOf(myFn{})))
if !ok || func() bool { _, ok := runtime.LookupType(k); return !ok }() {
runtime.RegisterType(reflect.TypeOf(myFn{}))
} Type guard
func typeRegistered(t reflect.Type) bool {
k, ok := runtime.TypeKey(reflectx.SkipPtr(t))
if !ok { return false }
_, found := runtime.LookupType(k)
return found
} Prevention
- Register every custom DoFn type in an init() function.
- Blank-import registration packages from the worker main.
- Write a unit test asserting typeRegistered(reflect.TypeOf(each DoFn)).
When it happens
Trigger: Calling EncodeMultiEdge on a transform whose DoFn is a structural/custom fn whose receiver type was never registered via runtime.RegisterType (or the beam package's init-time registration).
Common situations: Using a locally-defined or anonymous struct DoFn in a custom transform; registering types in a package the worker binary does not import; renaming/moving a type so registry init no longer runs.
Related errors
- empty type
- invalid float encoding for: %v
- could not unmarshal stream type coder from %v, stream must b
- could not unmarshal CoderRef from %v, failed to decode Coder
- failed to marshal iterable coder %v
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/8471c11164ec7f00.
Report an issue: GitHub.