{"record":{"id":"8d45c8a18628e963","repo":"apache/beam","slug":"no-nil-units","errorCode":null,"errorMessage":"no <nil> units","messagePattern":"no <nil> units","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/runtime/exec/plan.go","lineNumber":61,"sourceCode":"\n\t// TODO: there can be more than 1 DataSource in a bundle.\n\tsource *DataSource\n}\n\n// NewPlan returns a new bundle execution plan from the given units.\nfunc NewPlan(id string, units []Unit) (*Plan, error) {\n\tvar roots []Root\n\tvar pcols []*PCollection\n\tvar source *DataSource\n\tbf := bundleFinalizer{\n\t\tcallbacks:         []bundleFinalizationCallback{},\n\t\tlastValidCallback: time.Now(),\n\t}\n\tvar onTimers map[string]*ParDo\n\n\tfor _, u := range units {\n\t\tif u == nil {\n\t\t\treturn nil, errors.Errorf(\"no <nil> units\")\n\t\t}\n\t\tif r, ok := u.(Root); ok {\n\t\t\troots = append(roots, r)\n\t\t}\n\t\tif s, ok := u.(*DataSource); ok {\n\t\t\tsource = s\n\t\t}\n\t\tif p, ok := u.(*PCollection); ok {\n\t\t\tpcols = append(pcols, p)\n\t\t}\n\t\tif pd, ok := u.(*ParDo); ok && pd.HasOnTimer() {\n\t\t\tif onTimers == nil {\n\t\t\t\tonTimers = map[string]*ParDo{}\n\t\t\t}\n\t\t\tonTimers[pd.PID] = pd\n\t\t}\n\t\tif p, ok := u.(needsBundleFinalization); ok {\n\t\t\tp.AttachFinalizer(&bf)","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/runtime/exec/plan.go#L43-L79","documentation":"exec.NewPlan validates that no execution unit in the slice is nil before assembling roots and the data source. The library throws this error because a nil unit would panic later during plan execution; it is a defensive constructor check.","triggerScenarios":"Passing a slice of execution units containing a nil entry to exec.NewPlan, usually because a preceding construction step (e.g. building a ParDo or DataSource) failed silently or a slice append skipped an assignment.","commonSituations":"Test code building unit lists dynamically (TestFlatten, TestMultiplex style); pipeline translation bugs where an optional transform produces no unit.","solutions":["Filter or assert non-nil units before calling NewPlan.","Check the code that builds the units slice: a failed unit construction usually returns an error that was swallowed.","Add a guard in the plan-construction helper to return the earlier construction error instead of appending nil."],"exampleFix":"// before\nunits := append(units, maybeUnit) // maybeUnit may be nil\nplan, err := exec.NewPlan(id, units)\n// after\nif maybeUnit == nil {\n    return nil, fmt.Errorf(\"unit construction failed\")\n}\nunits := append(units, maybeUnit)\nplan, err := exec.NewPlan(id, units)","handlingStrategy":"validation","validationCode":"for i, u := range units {\n    if u == nil {\n        return fmt.Errorf(\"unit %d is nil before NewPlan\", i)\n    }\n}\nplan, err := exec.NewPlan(id, units)","typeGuard":null,"tryCatchPattern":"plan, err := exec.NewPlan(id, units)\nif err != nil {\n    if strings.Contains(err.Error(), \"no <nil> units\") {\n        log.Printf(\"unit construction produced nil; check builder error handling\")\n    }\n    return err\n}","preventionTips":["Check the error return of every unit constructor before appending to the units slice.","Never append a possibly-nil unit; return the construction error instead.","Add unit-slice assertions in plan-building helper functions."],"tags":["go","apache-beam","nil","validation"],"backgroundTag":"null-argument","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}