apache/beam · error
Scope is nil
Error message
Scope is nil
What it means
Graph.NewScope panics when the parent *Scope is nil. Every new scope in a Beam pipeline graph must descend from an existing scope so the graph remains connected; a nil parent indicates a mis-constructed pipeline.
Solutions
- Obtain the initial scope from the pipeline, e.g. beam.NewScope(p), before creating child scopes
- Fix the helper/initialization that produced the nil parent scope
- Guard custom transform constructors with a nil check on the incoming scope
Example fix
// before
sub := graph.NewScope(parent, "myTransform") // parent may be nil
// after
if parent == nil {
parent = beam.NewScope(p)
}
sub := graph.NewScope(parent, "myTransform") Defensive patterns
Strategy: validation
Validate before calling
if parent == nil {
return errors.New("nil scope passed to NewScope; obtain root scope via beam.NewScope(p)")
} Type guard
func validScope(s *graph.Scope) bool { return s != nil } Try / catch
func safeNewScope(g *graph.Graph, parent *graph.Scope, name string) (s *graph.Scope, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("newScope: %v", r) } }()
return g.NewScope(parent, name), nil
} Prevention
- Always derive the first scope from the pipeline (beam.NewScope(p))
- Handle error paths in helpers so they never return a nil scope
- Nil-check scope parameters in custom composite transforms
When it happens
Trigger: Calling graph.NewScope(nil, name), typically because a scope variable was never initialized or was lost through an API boundary.
Common situations: Storing the pipeline root scope in a struct field that was never set; helper functions returning nil scope on error paths that is then passed to NewScope; zero-value struct usage instead of p.NewScope(...) or beam.NewScope.
Related errors
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/b887fabb01d69340.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/graph/graph.go:52
root *Scope
}
// New returns an empty graph with the scope set to the root.
func New() *Graph {
root := &Scope{id: 0, Label: "root", Parent: nil}
return &Graph{root: root}
}
// Root returns the root scope of the graph.
func (g *Graph) Root() *Scope {
return g.root
}
// NewScope creates and returns a new scope that is a child of the supplied scope.
func (g *Graph) NewScope(parent *Scope, name string) *Scope {
if parent == nil {
panic("Scope is nil")
}
id := len(g.scopes) + 1
s := &Scope{id: id, Label: name, Parent: parent}
g.scopes = append(g.scopes, s)
return s
}
// NewEdge creates a new edge of the graph in the supplied scope.
func (g *Graph) NewEdge(parent *Scope) *MultiEdge {
if parent == nil {
panic("Scope is nil")
}
id := len(g.edges) + 1
e := &MultiEdge{id: id, parent: parent}
g.edges = append(g.edges, e)
return e
}
View on GitHub (pinned to 12126d8942)