{"record":{"id":"cf60f2d2f7c069d8","repo":"apache/beam","slug":"bad-output-type","errorCode":null,"errorMessage":"bad output type","messagePattern":"bad output type","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/runtime/graphx/serialize.go","lineNumber":82,"sourceCode":"\t}\n\n\tfor _, in := range edge.Input {\n\t\tkind, err := encodeInputKind(in.Kind)\n\t\tif err != nil {\n\t\t\twrapped := errors.Wrap(err, \"bad input type\")\n\t\t\treturn nil, errors.WithContextf(wrapped, \"encoding userfn %v\", edge)\n\t\t}\n\t\tt, err := encodeFullType(in.Type)\n\t\tif err != nil {\n\t\t\twrapped := errors.Wrap(err, \"bad input type\")\n\t\t\treturn nil, errors.WithContextf(wrapped, \"encoding userfn %v\", edge)\n\t\t}\n\t\tret.Inbound = append(ret.Inbound, &v1pb.MultiEdge_Inbound{Kind: kind, Type: t})\n\t}\n\tfor _, out := range edge.Output {\n\t\tt, err := encodeFullType(out.Type)\n\t\tif err != nil {\n\t\t\twrapped := errors.Wrap(err, \"bad output type\")\n\t\t\treturn nil, errors.WithContextf(wrapped, \"encoding userfn %v\", edge)\n\t\t}\n\t\tret.Outbound = append(ret.Outbound, &v1pb.MultiEdge_Outbound{Type: t})\n\t}\n\treturn ret, nil\n}\n\n// DecodeMultiEdge converts the wire representation into the preprocessed\n// components representing that edge. We deserialize to components to avoid\n// inserting the edge into a graph or creating a detached edge.\nfunc DecodeMultiEdge(edge *v1pb.MultiEdge) (graph.Opcode, *graph.Fn, *window.Fn, []*graph.Inbound, []*graph.Outbound, error) {\n\tvar u *graph.Fn\n\tvar wfn *window.Fn\n\tvar inbound []*graph.Inbound\n\tvar outbound []*graph.Outbound\n\n\topcode := graph.Opcode(edge.Opcode)\n","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/runtime/graphx/serialize.go#L64-L100","documentation":"EncodeMultiEdge wraps encodeFullType failures for an output as 'bad output type' (context 'encoding userfn'). The output PCollection's FullType could not be encoded into MultiEdge_Outbound, aborting graph serialization.","triggerScenarios":"EncodeMultiEdge iterating edge.Output where encodeFullType(out.Type) fails — output typed with functions, channels, or otherwise unrepresentable Go types.","commonSituations":"Custom DoFn outputs using unsupported Go types; constructing graph edges by hand; mismatched beam versions producing types the encoder can't handle.","solutions":["Read the inner encodeFullType error for the concrete type problem","Change the output element type to a supported encodable Go type","Register custom types used in outputs","Verify beam dependency versions are consistent"],"exampleFix":"// before\nout := beam.SideInput... typed via reflect.TypeOf(func(){}) // unencodable\n// after\nout typed as a struct or primitive type supported by encodeFullType","handlingStrategy":"validation","validationCode":"for _, out := range edge.Output {\n  if !isEncodableGoType(out.Type.Type()) {\n    return fmt.Errorf(\"output type %s not encodable\", out.Type.Type())\n  }\n}","typeGuard":"func isEncodableGoType(t reflect.Type) bool {\n  switch t.Kind() {\n  case reflect.Chan, reflect.Func, reflect.UnsafePointer:\n    return false\n  }\n  return true\n}","tryCatchPattern":"t, err := encodeFullType(out.Type)\nif err != nil {\n  return fmt.Errorf(\"output type %v not encodable: %w\", out.Type.Type(), err)\n}","preventionTips":["Emit outputs of supported element types from DoFns","Register custom output structs","Avoid func/chan-typed outputs","Validate graph encoding before remote submission"],"tags":["go","beam","serialization","types"],"backgroundTag":"json-marshal-failed","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"}