gastownhall/beads · error
gate: target step %q not found
Error message
gate: target step %q not found
What it means
After validating a gate's condition, applyGatesWithMap looks up Gate[i].Before in the workflow's step map to attach the gate label to that step. This error is returned when the target step ID does not exist in the steps list. The gate can only guard a step the workflow actually defines, so the library fails with the offending ID.
Source
Thrown at internal/formula/controlflow.go:533
for _, gate := range compose.Gate {
// Validate the gate rule
if gate.Before == "" {
return fmt.Errorf("gate: before is required")
}
if gate.Condition == "" {
return fmt.Errorf("gate: condition is required")
}
// Validate the condition syntax
_, err := ParseCondition(gate.Condition)
if err != nil {
return fmt.Errorf("gate: invalid condition %q: %w", gate.Condition, err)
}
// Find the target step
step, ok := stepMap[gate.Before]
if !ok {
return fmt.Errorf("gate: target step %q not found", gate.Before)
}
// Add gate label for runtime evaluation using JSON for unambiguous parsing
gateMeta := map[string]string{"condition": gate.Condition}
gateJSON, _ := json.Marshal(gateMeta)
gateLabel := fmt.Sprintf("gate:%s", string(gateJSON))
step.Labels = appendUnique(step.Labels, gateLabel)
}
return nil
}
// ApplyControlFlow applies all control flow operators in the correct order:
// 1. Loops (expand iterations)
// 2. Branches (wire fork-join dependencies)
// 3. Gates (add condition labels)
//
// Returns a new steps slice. The original steps slice is not modified.View on GitHub (pinned to 71377f2769)
Solutions
- Correct the gate's `before` value to match an existing step ID exactly
- Confirm the target step is still defined and wasn't renamed or removed in a recent edit
- Check for exact-match issues (case, whitespace) between the gate's before value and the step ID
- If the step is produced by loop expansion, use the expanded step ID or gate the loop's source step
Example fix
// before (compose rules)
gate: [{before: deploy-prod, condition: "label:critical"}]
// steps define "deploy" only
// after
gate: [{before: deploy, condition: "label:critical"}] Defensive patterns
Strategy: validation
Validate before calling
func validateGateTargets(steps []*Step, compose *ComposeRules) error {
ids := make(map[string]bool, len(steps))
for _, s := range steps {
ids[s.ID] = true
}
for _, g := range compose.Gate {
if g.Before != "" && !ids[g.Before] {
return fmt.Errorf("gate targets unknown step %q", g.Before)
}
}
return nil
} Try / catch
if _, err := formula.ApplyControlFlow(steps, compose); err != nil {
var target string
if n, _ := fmt.Sscanf(err.Error(), "gate: target step %q not found", &target); n == 1 {
return fmt.Errorf("workflow config error: gate targets unknown step %q; defined steps: %v", target, stepIDs(steps))
}
return err
} Prevention
- Reference gate targets from the same ID list that defines steps, not by hand
- Re-check gate rules whenever steps are renamed or removed
- Match step IDs exactly — no case or whitespace drift
- Run a config lint that cross-checks gate.before against defined step IDs before execution
When it happens
Trigger: Calling ApplyGates or ApplyControlFlow with a gate whose Before field names a step absent from the steps slice — a typo, a renamed/deleted step, a step created by loop expansion under a different ID, or an ID with case/whitespace mismatch.
Common situations: Config referencing a step that was renamed in a refactor; gate written against a step in a different workflow file; copy-pasted gate rules not updated for the new workflow's step IDs; steps removed by an earlier edit while gates still point at them.
Related errors
- branch: parallel step %q not found
- gate: before is required
- gate: condition is required
- formula %q not accessible: %w
- loop %q: max must be positive
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/39b8296a01809a13.
Report an issue: GitHub.