{"record":{"id":"ef43b06866f7db6e","repo":"apache/beam","slug":"bad-function-type","errorCode":null,"errorMessage":"bad function type","messagePattern":"bad function type","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/runtime/graphx/serialize.go","lineNumber":222,"sourceCode":"\treturn d.Nanoseconds() / 1e6\n}\n\nfunc ms2duration(d int64) time.Duration {\n\treturn time.Duration(d) * time.Millisecond\n}\n\n// encodeFn encodes a graph.Fn into a v1pb.Fn proto message.\n// All string fields in the DoFn struct must be UTF-8 compliant. The vet runner\n// (--beam_strict) will detect any non-UTF8 strings that would fail during JSON serialization.\n// The check will be skipped for subtypes that implement the MarshalJSON and\n// UnmarshalJSON interface methods.\nfunc encodeFn(u *graph.Fn) (*v1pb.Fn, error) {\n\tswitch {\n\tcase u.DynFn != nil:\n\t\tgen := reflectx.FunctionName(u.DynFn.Gen)\n\t\tt, err := encodeType(u.DynFn.T)\n\t\tif err != nil {\n\t\t\twrapped := errors.Wrap(err, \"bad function type\")\n\t\t\treturn nil, errors.WithContextf(wrapped, \"encoding dynamic DoFn %v\", u)\n\t\t}\n\t\treturn &v1pb.Fn{Dynfn: &v1pb.DynFn{\n\t\t\tName: u.DynFn.Name,\n\t\t\tType: t,\n\t\t\tData: u.DynFn.Data,\n\t\t\tGen:  gen,\n\t\t}}, nil\n\n\tcase u.Fn != nil:\n\t\tfn, err := encodeUserFn(u.Fn)\n\t\tif err != nil {\n\t\t\twrapped := errors.Wrap(err, \"bad userfn\")\n\t\t\treturn nil, errors.WithContextf(wrapped, \"encoding DoFn %v\", u)\n\t\t}\n\t\treturn &v1pb.Fn{Fn: fn}, nil\n\n\tcase u.Recv != nil:","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/runtime/graphx/serialize.go#L204-L240","documentation":"encodeFn serializes a graph.Fn. For a dynamically generated DoFn (u.DynFn), it must serialize the generator's type via encodeType(u.DynFn.T); if that type cannot be encoded (unregistered or unresolvable type), the error is wrapped as \"bad function type\". DynFn types must be registered in the runtime type registry.","triggerScenarios":"encodeFn (called from EncodeMultiEdge) encounters a DynFn whose generator function type u.DynFn.T is not registered/encodable — e.g. the DoFn was generated in code whose type wasn't registered with the type registry.","commonSituations":"Dynamic DoFns created by code generators in packages that never call beam.RegisterType; types from anonymous or internal packages; model serialization across different binaries with differing registries.","solutions":["Register the dynamic DoFn's type with beam.RegisterType before encoding the pipeline","Ensure the generator function is a named package-level function whose type is resolvable","Check encodeType on the failing type in isolation to see the underlying reason","Avoid anonymous types / anonymous packages in generated DoFn code"],"exampleFix":"// before: dyn fn type never registered\n// after\nfunc init() {\n\tbeam.RegisterType(reflect.TypeOf((*myDynFn)(nil)).Elem())\n}","handlingStrategy":"validation","validationCode":"t := reflect.TypeOf(dynFnType)\nif _, ok := runtime.LookupType(runtime.TypeKey(reflectx.SkipPtr(t))); !ok {\n\treturn fmt.Errorf(\"register type %v before encoding pipeline\", t)\n}","typeGuard":"func isRegistered(t reflect.Type) bool {\n\t_, ok := runtime.LookupType(runtime.TypeKey(reflectx.SkipPtr(t)))\n\treturn ok\n}","tryCatchPattern":"mb, err := graphx.Marshal(model)\nif err != nil && strings.Contains(err.Error(), \"bad function type\") {\n\treturn fmt.Errorf(\"dyn DoFn type unregistered: %w\", err)\n}","preventionTips":["Register dynamic DoFn types in init()","Use named generators in stable packages","Round-trip encode/decode tests for pipelines with DynFns","Avoid anonymous/internal types in generated DoFns"],"tags":["go","beam","dofn","serialization"],"backgroundTag":"type-not-registered","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}