apache/beam · error
bad symbol
Error message
bad symbol %v
What it means
decodeFn, when reconstructing a dynamic DoFn on the worker, calls runtime.ResolveFunction with the encoded symbol name; failure is wrapped as "bad symbol". The symbol registered during pipeline construction could not be resolved in the worker binary's function registry.
Solutions
- Ensure the package defining the dynamic fn generator is imported (even with a blank import) by the worker main.
- Verify the generator is registered with the same symbol at init via runtime.RegisterFunction.
- Check for version mismatch between the job submission binary and the worker image.
- Confirm the container image used by the runner includes the user's compiled code.
Example fix
// before // worker main.go omits the package // after import _ "myproject/internal/dofngens" // pulls in runtime.RegisterFunction calls
Defensive patterns
Strategy: validation
Validate before calling
if _, ok := runtime.LoadFunction(genSymbol); !ok {
return fmt.Errorf("generator symbol %q not registered in this binary", genSymbol)
} Try / catch
gen, err := runtime.ResolveFunction(u.Dynfn.Gen, genFnType)
if err != nil {
return fmt.Errorf("missing generator %q: ensure its package is imported by the worker: %w", u.Dynfn.Gen, err)
} Prevention
- Blank-import all packages registering dynamic fn generators from the worker main.
- Register generators with stable symbol names via runtime.RegisterFunction at init.
- Rebuild the worker container from the same commit as the submission.
When it happens
Trigger: DecodeMultiEdge decoding a DynFn whose Gen symbol is absent from the worker's runtime registry — the generator function was not linked into the worker binary or its package wasn't imported.
Common situations: Cross-language/custom containers missing the package that registers the generator; refactored or renamed generator functions between submit and execution; worker built without the user package.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/10a314dd8ef23585.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/serialize.go:273
}
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)
}
}
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 {View on GitHub (pinned to 12126d8942)