gastownhall/beads · error
expand: target step %q not found
Error message
expand: target step %q not found
What it means
ApplyExpansions returns this error when a compose.Expand rule targets a step ID that is not present in the formula's steps (or children) at the time the rule is processed. Expansion replaces a target step with the template from the referenced expansion formula, so the target must exist. The step map is rebuilt after each expansion, but the referenced target must exist when its rule is reached.
Source
Thrown at internal/formula/expand.go:54
return steps, nil
}
if len(compose.Expand) == 0 && len(compose.Map) == 0 {
return steps, nil
}
// Build a map of step ID -> step for quick lookup
stepMap := buildStepMap(steps)
// Track which steps have been expanded (to avoid double expansion)
expanded := make(map[string]bool)
// Apply expand rules first (specific targets)
result := steps
for _, rule := range compose.Expand {
targetStep, ok := stepMap[rule.Target]
if !ok {
return nil, fmt.Errorf("expand: target step %q not found", rule.Target)
}
if expanded[rule.Target] {
continue // Already expanded
}
// Load the expansion formula
expFormula, err := parser.LoadByName(rule.With)
if err != nil {
return nil, fmt.Errorf("expand: loading %q: %w", rule.With, err)
}
if expFormula.Type != TypeExpansion {
return nil, fmt.Errorf("expand: %q is not an expansion formula (type=%s)", rule.With, expFormula.Type)
}
if len(expFormula.Template) == 0 {
return nil, fmt.Errorf("expand: %q has no template steps", rule.With)View on GitHub (pinned to 71377f2769)
Solutions
- Check that the expand rule's Target exactly matches a step ID defined in the formula (including nested children)
- Reorder or consolidate expand rules so a step is not targeted after an earlier rule replaced it
- Use a map rule with a glob Select instead of expand if you need pattern-based targeting of generated steps
- Verify against the step list remaining after prior expansions have been applied
Example fix
// before
expand:
- target: reviw
with: review-checklist
// after
expand:
- target: review
with: review-checklist Defensive patterns
Strategy: validation
Validate before calling
func validateExpandTargets(steps []*Step, compose *ComposeRules) error {
ids := buildStepMap(steps)
for _, r := range compose.Expand {
if _, ok := ids[r.Target]; !ok {
return fmt.Errorf("expand target %q does not exist", r.Target)
}
}
return nil
} Try / catch
result, err := ApplyExpansions(steps, compose, parser)
if err != nil {
var target string
if _, scanErr := fmt.Sscanf(err.Error(), "expand: target step %q not found", &target); scanErr == nil {
return fmt.Errorf("fix compose.expand: step %q missing or already replaced", target)
}
return err
} Prevention
- Keep expand targets pointing at base steps that earlier rules do not replace
- Expand targets in dependency order; an earlier expansion removes the original ID
- Prefer map rules with globs for generated/renamed steps
- Add a formula linter that cross-checks expand targets against defined step IDs
When it happens
Trigger: Calling ApplyExpansions(steps, compose, parser) with compose.Expand[].Target naming a step ID that does not exist, was already replaced by an earlier expansion rule, or is misspelled.
Common situations: Typo in the expand target ID; an earlier expand/map rule already replaced the target step so its ID no longer exists; expanding a step that only exists before other expansions changed the step list.
Related errors
- expand: loading %q: %w
- applying expansions: %w
- applying expansions to %q: %w
- standalone expansion %q: %w
- formula %q not accessible: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/60d62d8d585d68fd.
Report an issue: GitHub.