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

  1. Ensure the package defining the dynamic fn generator is imported (even with a blank import) by the worker main.
  2. Verify the generator is registered with the same symbol at init via runtime.RegisterFunction.
  3. Check for version mismatch between the job submission binary and the worker image.
  4. 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

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)