{"record":{"id":"a1bb10e5bc537207","repo":"gastownhall/beads","slug":"applying-loops-w","errorCode":null,"errorMessage":"applying loops: %w","messagePattern":"applying loops: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/controlflow.go","lineNumber":558,"sourceCode":"\t\tstep.Labels = appendUnique(step.Labels, gateLabel)\n\t}\n\n\treturn nil\n}\n\n// ApplyControlFlow applies all control flow operators in the correct order:\n// 1. Loops (expand iterations)\n// 2. Branches (wire fork-join dependencies)\n// 3. Gates (add condition labels)\n//\n// Returns a new steps slice. The original steps slice is not modified.\nfunc ApplyControlFlow(steps []*Step, compose *ComposeRules) ([]*Step, error) {\n\tvar err error\n\n\t// Apply loops first (expands steps) - ApplyLoops already returns new slice\n\tsteps, err = ApplyLoops(steps)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"applying loops: %w\", err)\n\t}\n\n\t// Build stepMap once for branches and gates\n\t// No need to clone here since ApplyLoops already returned a new slice\n\tstepMap := buildStepMap(steps)\n\n\t// Apply branches (wires dependencies)\n\tif err := applyBranchesWithMap(stepMap, compose); err != nil {\n\t\treturn nil, fmt.Errorf(\"applying branches: %w\", err)\n\t}\n\n\t// Apply gates (adds labels)\n\tif err := applyGatesWithMap(stepMap, compose); err != nil {\n\t\treturn nil, fmt.Errorf(\"applying gates: %w\", err)\n\t}\n\n\treturn steps, nil\n}","sourceCodeStart":540,"sourceCodeEnd":576,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/controlflow.go#L540-L576","documentation":"ApplyControlFlow wraps any failure from ApplyLoops with 'applying loops: %w'. ApplyLoops expands loop rules (a step repeated over an items list or count) into multiple concrete steps. This error means one of the compose loop rules failed validation or expansion — typically a missing field or a loop target step ID that does not exist in the formula's step list.","triggerScenarios":"Calling ApplyControlFlow(steps, compose) where compose.Loops contains a rule whose Target does not match any step ID, or whose items/count fields are invalid, causing ApplyLoops to return an error.","commonSituations":"Formula YAML where a loop rule references a step ID with a typo or renamed ID; a loop rule added after the target step was deleted; refactorings that renamed steps without updating the compose loop section.","solutions":["Read the wrapped inner error (errors.Unwrap or %v of the returned error) — it names the offending loop rule and field","Check that every compose.Loops[].Target matches an existing step ID in the formula (including nested children)","Run/inspect the loop rule validation before calling ApplyControlFlow by calling ApplyLoops(steps) directly in a test","Fix or remove the invalid loop rule in the formula's compose section"],"exampleFix":"// before\ncompose:\n  loops:\n    - target: deploy-stp\n      items: [dev, prod]\n// after\ncompose:\n  loops:\n    - target: deploy-step\n      items: [dev, prod]","handlingStrategy":"validation","validationCode":"for _, lp := range compose.Loops {\n\tif lp.Target == \"\" {\n\t\treturn fmt.Errorf(\"loop rule missing target\")\n\t}\n\tfound := false\n\tvar walk func([]*Step)\n\twalk = func(ss []*Step) {\n\t\tfor _, s := range ss {\n\t\t\tif s.ID == lp.Target { found = true }\n\t\t\twalk(s.Children)\n\t\t}\n\t}\n\twalk(steps)\n\tif !found {\n\t\treturn fmt.Errorf(\"loop target %q not found in steps\", lp.Target)\n\t}\n}\n_, err := ApplyLoops(steps)\nreturn err","typeGuard":null,"tryCatchPattern":"expanded, err := ApplyControlFlow(steps, compose)\nif err != nil {\n\tvar inner error = errors.Unwrap(err)\n\tlog.Printf(\"control flow failed: %v (cause: %v)\", err, inner)\n\treturn fmt.Errorf(\"check compose loop rules: %w\", err)\n}","preventionTips":["Keep step IDs and loop targets in sync; rename via search across the compose section","Add a unit test that runs ApplyLoops on every formula in the repo","Validate compose rules at formula-parse time rather than at apply time","Avoid referencing steps that later control-flow or expansion passes may remove"],"tags":["go","formula","control-flow","loop-expansion"],"backgroundTag":"compose-rule-target-not-found","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}