apache/beam · error
bad type
Error message
bad type
What it means
decodeFn fails to decode the dynamic DoFn's receiver type from the encoded type descriptor (decodeType on u.Dynfn.Type), wrapped as "bad type". The type referenced in the pipeline proto cannot be reconstructed in the worker's runtime type registry.
Solutions
- Register the receiver type via runtime.RegisterType in a package imported by the worker.
- Rebuild the worker/container from the same code revision as the pipeline submission.
- Verify with runtime.LookupType(runtime.TypeKey(...)) in the worker that the type resolves.
- Align Beam Go SDK versions between submitter and worker image.
Example fix
// before
// worker: type not registered anywhere
// after
// package imported by worker main
func init() { runtime.RegisterType(reflect.TypeOf(myFn{})) } Defensive patterns
Strategy: validation
Validate before calling
k, _ := runtime.TypeKey(reflectx.SkipPtr(reflect.TypeOf(myFn{})))
if _, ok := runtime.LookupType(k); !ok {
runtime.RegisterType(reflect.TypeOf(myFn{}))
} Type guard
func typeResolvable(t reflect.Type) bool {
k, ok := runtime.TypeKey(reflectx.SkipPtr(t))
if !ok { return false }
_, ok = runtime.LookupType(k)
return ok
} Prevention
- Import type-registration packages in the worker binary.
- Keep DoFn type names/paths stable across deploys.
- Test decode paths in worker-like binaries, not just the driver.
When it happens
Trigger: DecodeMultiEdge decoding a DynFn whose encoded Type refers to a type not registered/lookup-able in the worker process.
Common situations: Type registered only in the driver; type renamed or moved between submit and run; worker container built from different code than the submitter.
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
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/4e7f963c3ced8ea0.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/serialize.go:279
}
return &v1pb.Fn{Type: typ, Opt: string(data)}, nil
default:
return nil, errors.Errorf("failed to encode DoFn %v, missing fn", u)
}
}
func decodeFn(u *v1pb.Fn) (*graph.Fn, error) {
if u.Dynfn != nil {
gen, err := runtime.ResolveFunction(u.Dynfn.Gen, genFnType)
if err != nil {
wrapped := errors.Wrapf(err, "bad symbol %v", u.Dynfn.Gen)
return nil, errors.WithContextf(wrapped, "decoding dynamic DoFn %v", u)
}
t, err := decodeType(u.Dynfn.Type)
if err != nil {
wrapped := errors.Wrap(err, "bad type")
return nil, errors.WithContextf(wrapped, "failed to decode dynamic DoFn %v", u)
}
return graph.NewFn(&graph.DynFn{
Name: u.Dynfn.Name,
T: t,
Data: u.Dynfn.Data,
Gen: gen.(func(string, reflect.Type, []byte) reflectx.Func),
})
}
if u.Fn != nil {
fn, err := decodeUserFn(u.Fn)
if err != nil {
wrapped := errors.Wrap(err, "failed to decode userfn")
return nil, errors.WithContextf(wrapped, "decoding DoFn %v", u)
}
fx, err := funcx.New(reflectx.MakeFunc(fn))
if err != nil {
wrapped := errors.Wrap(err, "failed to construct userfn")View on GitHub (pinned to 12126d8942)