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

  1. Obtain the initial scope from the pipeline, e.g. beam.NewScope(p), before creating child scopes
  2. Fix the helper/initialization that produced the nil parent scope
  3. 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

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)