{"record":{"id":"fb4713db77f83199","repo":"apache/beam","slug":"node-v-in-graph-is-unconnected","errorCode":null,"errorMessage":"node %v in graph is unconnected","messagePattern":"node (.+?) in graph is unconnected","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/graph.go","lineNumber":106,"sourceCode":"\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 {\n\t\tif _, ok := nodes[n]; !ok {\n\t\t\treturn nil, nil, errors.Errorf(\"node %v is reachable by edge %v, but it's not in same graph\", n.id, e.id)\n\t\t}\n\t}\n\treturn g.edges, g.nodes, nil\n}\n\nfunc (g *Graph) String() string {\n\tvar nodes []string\n\tfor _, node := range g.nodes {\n\t\tnodes = append(nodes, node.String())\n\t}\n\tvar edges []string\n\tfor _, edge := range g.edges {\n\t\tedges = append(edges, edge.String())","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/graph.go#L88-L124","documentation":"Graph.Build() checks that every node in g.nodes is reachable via at least one MultiEdge output. A node with no incoming edge means it's disconnected from the pipeline (nothing consumes it), so Build returns 'node %v in graph is unconnected'.","triggerScenarios":"Creating a node (e.g. via beam.Impulse/beam.Create output or manual g.NewNode) without wiring it as input to any transform before calling Build().","commonSituations":"Manually constructing graphs with the low-level API and forgetting to connect an output; a transform whose output PCollection is dropped silently in custom code; SDK bugs when composing custom composite transforms.","solutions":["Connect the orphan node to a downstream transform (e.g. pass it as an input to beam.ParDo or a sink like beam.io.Write).","If the PCollection is intentionally unused, remove the transform producing it.","When hand-building graphs, register the node via an edge (g.NewEdge and set Input/Output) before Build().","Review custom composite transform expansion so all outputs are either consumed or deliberately rooted."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Consume every PCollection produced by a transform, or don't produce it.","When using the low-level graph API, wire each node into an edge before Build()."],"tags":["beam","go","graph","dag"],"backgroundTag":"invalid-state-transition","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"}