apache/beam · error
no root units
Error message
no root units
What it means
A valid plan must contain at least one Root unit (e.g. DataSource). exec.NewPlan throws this error when the supplied units slice contains no unit implementing the Root interface, since a plan without a source of data cannot execute.
Solutions
- Ensure a *DataSource unit is included in the units passed to NewPlan.
- Check that the root unit's type assertion (u.(Root)) can succeed - the unit must implement the Root interface.
- Review pipeline translation code to confirm the source transform maps to a DataSource unit.
Example fix
// before
units := []exec.Unit{pardo1, pardo2}
plan, err := exec.NewPlan(id, units) // no root
// after
units := []exec.Unit{dataSource, pardo1, pardo2}
plan, err := exec.NewPlan(id, units) Defensive patterns
Strategy: validation
Validate before calling
hasRoot := false
for _, u := range units {
if _, ok := u.(exec.Root); ok {
hasRoot = true
break
}
}
if !hasRoot {
return fmt.Errorf("units must include a Root (DataSource)")
}
plan, err := exec.NewPlan(id, units) Type guard
func hasRootUnit(units []exec.Unit) bool {
for _, u := range units {
if _, ok := u.(exec.Root); ok {
return true
}
}
return false
} Try / catch
plan, err := exec.NewPlan(id, units)
if err != nil {
if strings.Contains(err.Error(), "no root units") {
return fmt.Errorf("pipeline translation produced no DataSource: %w", err)
}
return err
} Prevention
- Always include a *DataSource in the units passed to NewPlan.
- Verify transform translation maps source transforms to DataSource units.
- Write a test asserting every constructed plan contains exactly one root.
When it happens
Trigger: Calling NewPlan with only non-root units (e.g. only ParDos/Flatten without a DataSource), or a translation bug where the DataSource unit failed a type assertion (it must be a concrete *DataSource).
Common situations: Custom runners or tests constructing plans from transform lists without including the DataSource; refactors changing unit types so the root type no longer implements Root.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- capacity of cache cannot be negative, got
- could not unmarshal iterable coder from
- could not unmarshal nullable coder from
- could not unmarshal sharded_key coder from
- empty pipeline
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/794e0d46558a0ac0.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/core/runtime/exec/plan.go:83
}
if s, ok := u.(*DataSource); ok {
source = s
}
if p, ok := u.(*PCollection); ok {
pcols = append(pcols, p)
}
if pd, ok := u.(*ParDo); ok && pd.HasOnTimer() {
if onTimers == nil {
onTimers = map[string]*ParDo{}
}
onTimers[pd.PID] = pd
}
if p, ok := u.(needsBundleFinalization); ok {
p.AttachFinalizer(&bf)
}
}
if len(roots) == 0 {
return nil, errors.Errorf("no root units")
}
if len(onTimers) > 0 {
source.OnTimerTransforms = onTimers
}
return &Plan{
id: id,
status: Initializing,
roots: roots,
units: units,
pcols: pcols,
bf: &bf,
source: source,
}, nil
}
func (p *Plan) getStatus() Status {View on GitHub (pinned to 12126d8942)