apache/beam · error
bad encoding function
Error message
bad encoding function
What it means
encodeCustomCoder serializes a coder.CustomCoder, calling encodeUserFn on its encoding function c.Enc. If the encoding function cannot be represented as a serializable user function (e.g. it is a closure, a non-top-level function, or defined in a package that cannot be resolved), the error is wrapped as "bad encoding function". Beam requires custom coder functions to be named, top-level functions in a registered package.
Source
Thrown at sdks/go/pkg/beam/core/runtime/graphx/serialize.go:144
t, err := decodeFullType(out.Type)
if err != nil {
wrapped := errors.Wrap(err, "bad output type")
return "", nil, nil, nil, nil, errors.WithContextf(wrapped, "decoding userfn %v", edge)
}
outbound = append(outbound, &graph.Outbound{Type: t})
}
return opcode, u, wfn, inbound, outbound, nil
}
func encodeCustomCoder(c *coder.CustomCoder) (*v1pb.CustomCoder, error) {
t, err := encodeType(c.Type)
if err != nil {
return nil, errors.WithContextf(err, "encoding custom coder %v for type %v", c, c.Type)
}
enc, err := encodeUserFn(c.Enc)
if err != nil {
wrapped := errors.Wrap(err, "bad encoding function")
return nil, errors.WithContextf(wrapped, "encoding custom coder %v", c)
}
dec, err := encodeUserFn(c.Dec)
if err != nil {
wrapped := errors.Wrap(err, "bad decoding function")
return nil, errors.WithContextf(wrapped, "encoding custom coder %v", c)
}
ret := &v1pb.CustomCoder{
Name: c.Name,
Type: t,
Enc: enc,
Dec: dec,
}
return ret, nil
}
func decodeCustomCoder(c *v1pb.CustomCoder) (*coder.CustomCoder, error) {View on GitHub (pinned to 12126d8942)
Solutions
- Define the encoding function as a named, package-level function
- Avoid closures, bound methods, and anonymous funcs in custom coders
- Verify encodeUserFn can resolve the function's fully qualified name (use reflectx.FunctionName to test)
- Move coder functions out of test/generated code into a stable package
Example fix
// before
enc := func(v T) []byte { ... }
c, _ := coder.NewCustomCoder("myCoder", typ, enc, dec)
// after
func encodeT(v T) []byte { ... }
c, _ := coder.NewCustomCoder("myCoder", typ, encodeT, decodeT) Defensive patterns
Strategy: type-guard
Validate before calling
func isValidCoderFn(f interface{}) bool {
v := reflect.ValueOf(f)
return v.Kind() == reflect.Func && v.Pointer() != 0 &&
runtime.IsFunction(v) && !isClosureOrMethodValue(v)
} Type guard
func isNamedFunc(f interface{}) bool {
name := reflectx.FunctionName(f)
return name != "" && !strings.Contains(name, "func") && !strings.Contains(name, "-")
} Try / catch
ref, err := graphx.EncodeCoderRef(c)
if err != nil && strings.Contains(err.Error(), "bad encoding function") {
return fmt.Errorf("coder %v uses non-serializable enc fn: %w", c, err)
} Prevention
- Only use package-level named functions in coder.NewCustomCoder
- Never use closures or method values as coder enc/dec
- Define coders in stable, importable packages
- Add a unit test that encodes every custom coder you ship
When it happens
Trigger: Creating a coder.NewCustomCoder whose enc function is an anonymous/closure function, a method value, or a function in an internal/unregistered package, then calling Add or EncodeCoderRef to serialize the coder.
Common situations: Passing inline func literals to NewCustomCoder; using methods bound to an instance; defining coders in test binaries or generated code that cannot be referenced by name at decode time.
Related errors
- varint too long
- failed to marshal custom coder %v
- custom coders must be length prefixed: %+v
- bad decoding function
- value %v not encodable with %v
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/dbfcbbca62ab9382.
Report an issue: GitHub.