{"record":{"id":"d22c5222977ed331","repo":"gastownhall/beads","slug":"branch-steps-is-required","errorCode":null,"errorMessage":"branch: steps is required","messagePattern":"branch: steps is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/controlflow.go","lineNumber":449,"sourceCode":"\n\treturn cloned, nil\n}\n\n// applyBranchesWithMap applies branch rules using a pre-built stepMap.\n// This is the internal implementation used by both ApplyBranches and ApplyControlFlow.\n// The stepMap entries are modified in place.\nfunc applyBranchesWithMap(stepMap map[string]*Step, compose *ComposeRules) error {\n\tif compose == nil || len(compose.Branch) == 0 {\n\t\treturn nil\n\t}\n\n\tfor _, branch := range compose.Branch {\n\t\t// Validate the branch rule\n\t\tif branch.From == \"\" {\n\t\t\treturn fmt.Errorf(\"branch: from is required\")\n\t\t}\n\t\tif len(branch.Steps) == 0 {\n\t\t\treturn fmt.Errorf(\"branch: steps is required\")\n\t\t}\n\t\tif branch.Join == \"\" {\n\t\t\treturn fmt.Errorf(\"branch: join is required\")\n\t\t}\n\n\t\t// Verify all steps exist\n\t\tif _, ok := stepMap[branch.From]; !ok {\n\t\t\treturn fmt.Errorf(\"branch: from step %q not found\", branch.From)\n\t\t}\n\t\tif _, ok := stepMap[branch.Join]; !ok {\n\t\t\treturn fmt.Errorf(\"branch: join step %q not found\", branch.Join)\n\t\t}\n\t\tfor _, stepID := range branch.Steps {\n\t\t\tif _, ok := stepMap[stepID]; !ok {\n\t\t\t\treturn fmt.Errorf(\"branch: parallel step %q not found\", stepID)\n\t\t\t}\n\t\t}\n","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/controlflow.go#L431-L467","documentation":"Each branch rule must list the Steps that run in parallel between From and Join. applyBranchesWithMap rejects a rule with an empty Steps list because a branch with no parallel steps does nothing and likely indicates a misconfigured compose section.","triggerScenarios":"ApplyBranches or ApplyControlFlow encountering a compose.Branch entry with no `steps` entries (empty list or omitted key).","commonSituations":"YAML `steps:` key present but with no list items; all step entries commented out; programmatically built ComposeRules with a nil Steps slice.","solutions":["List the parallel step IDs under the branch rule's `steps:` key","Verify the listed steps actually exist elsewhere in the formula (a later check requires it)","Uncomment or restore step entries that were accidentally removed"],"exampleFix":"# before\nbranch:\n  - from: start\n    join: end\n# after\nbranch:\n  - from: start\n    steps: [a, b]\n    join: end","handlingStrategy":"validation","validationCode":"for i, b := range compose.Branch {\n\tif len(b.Steps) == 0 {\n\t\treturn fmt.Errorf(\"branch[%d]: steps is required\", i)\n\t}\n}","typeGuard":null,"tryCatchPattern":"steps, err := formula.ApplyBranches(steps, compose)\nif err != nil {\n\tif strings.Contains(err.Error(), \"steps is required\") {\n\t\treturn fmt.Errorf(\"compose branch missing 'steps': %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Verify branch steps lists are non-empty after YAML parsing","Don't comment out all step entries without removing the rule","Validate ComposeRules structs before passing to ApplyBranches"],"tags":["go","formula","branch","validation","compose"],"backgroundTag":"missing-required-field","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}