{"record":{"id":"23c61ef447e4c4ab","repo":"apache/beam","slug":"node-v-in-graph-has-undefined-coder","errorCode":null,"errorMessage":"node %v in graph has undefined coder","messagePattern":"node (.+?) in graph has undefined coder","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/graph.go","lineNumber":91,"sourceCode":"\tif !typex.IsBound(t) {\n\t\tpanic(fmt.Sprintf(\"Node type not bound: %v\", t))\n\t}\n\tid := len(g.nodes) + 1\n\tn := &Node{id: id, t: t, w: w, bounded: bounded}\n\tg.nodes = append(g.nodes, n)\n\treturn n\n}\n\n// Build performs finalization on the graph. It verifies the correctness of the\n// graph structure, typechecks the plan and returns a slice of the edges in\n// the graph.\nfunc (g *Graph) Build() ([]*MultiEdge, []*Node, error) {\n\t// Build a map of all nodes listed in g.nodes.\n\tnodes := make(map[*Node]bool)\n\tfor _, n := range g.nodes {\n\t\tnodes[n] = true\n\t\tif n.Coder == nil {\n\t\t\treturn nil, nil, errors.Errorf(\"node %v in graph has undefined coder\", n.id)\n\t\t}\n\t}\n\t// Build a map of all nodes that are reachable by g.edges.\n\treachable := make(map[*Node]*MultiEdge)\n\tfor _, e := range g.edges {\n\t\tfor _, i := range e.Input {\n\t\t\treachable[i.From] = e\n\t\t}\n\t\tfor _, o := range e.Output {\n\t\t\treachable[o.To] = e\n\t\t}\n\t}\n\tfor n := range nodes {\n\t\tif _, ok := reachable[n]; !ok {\n\t\t\treturn nil, nil, errors.Errorf(\"node %v in graph is unconnected\", n.id)\n\t\t}\n\t}\n\tfor n, e := range reachable {","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/graph.go#L73-L109","documentation":"Graph.Build() finalizes the Beam DAG and verifies every node has a coder (the serialization spec for its element type). During expansion/translation Beam normally assigns coders automatically; a nil coder means graph construction left a node untyped, so Build refuses to proceed with 'node %v in graph has undefined coder'.","triggerScenarios":"Calling g.Build() after adding edges whose input/output nodes were never given a coder, typically from custom transform construction (beam.Create with unsupported types, custom DoFn signatures Beam can't infer, or manually assembled Graphs).","commonSituations":"Using a custom DoFn whose ProcessElement parameter type can't be encoded (e.g. interface{}, chan, func types); building nodes directly via the low-level graph API without setting Coder; SDK/runner bugs when inserting cross-language transforms.","solutions":["Find the DoFn/transform producing that node and give ProcessElement concrete encodable types (no interface{}, func, or chan).","If using the low-level graph API, set n.Coder explicitly before Build().","Check for a Beam SDK bug — search the error's node id against your pipeline; upgrade to the latest Beam release.","Register custom types with beam.Encoder/coder registration so inference succeeds."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, _, err := g.Build(); err != nil {\n    if strings.Contains(err.Error(), \"undefined coder\") {\n        // inspect node id, fix producing DoFn types or set Coder explicitly\n        log.Fatalf(\"coder inference failed: %v\", err)\n    }\n    return err\n}","preventionTips":["Avoid interface{}, func, or chan types in DoFn ProcessElement parameters.","Register custom types for coder inference before building pipelines."],"tags":["beam","go","graph","coder"],"backgroundTag":"internal-invariant-violation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}