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

  1. Check that the expand rule's Target exactly matches a step ID defined in the formula (including nested children)
  2. Reorder or consolidate expand rules so a step is not targeted after an earlier rule replaced it
  3. Use a map rule with a glob Select instead of expand if you need pattern-based targeting of generated steps
  4. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/60d62d8d585d68fd. Report an issue: GitHub.