gastownhall/beads · error

map: %q has no template steps

Error message

map: %q has no template steps

What it means

The map rule's `with:` formula is an expansion formula but defines no template steps. Like the expand variant, map cannot replace matched steps with an empty expansion, so it errors.

Source

Thrown at internal/formula/expand.go:117

		// Rebuild stepMap from result so subsequent iterations see resolved deps
		stepMap = buildStepMap(result)
	}

	// Apply map rules (pattern matching)
	for _, rule := range compose.Map {
		// Load the expansion formula
		expFormula, err := parser.LoadByName(rule.With)
		if err != nil {
			return nil, fmt.Errorf("map: loading %q: %w", rule.With, err)
		}

		if expFormula.Type != TypeExpansion {
			return nil, fmt.Errorf("map: %q is not an expansion formula (type=%s)", rule.With, expFormula.Type)
		}

		if len(expFormula.Template) == 0 {
			return nil, fmt.Errorf("map: %q has no template steps", rule.With)
		}

		// Merge formula default vars with rule overrides
		vars := mergeVars(expFormula, rule.Vars)

		// Find all matching steps (including nested children)
		// Rebuild stepMap to capture any changes from previous expansions
		stepMap = buildStepMap(result)
		var toExpand []*Step
		for id, step := range stepMap {
			if MatchGlob(rule.Select, id) && !expanded[id] {
				toExpand = append(toExpand, step)
			}
		}

		// Expand each matching step
		for _, targetStep := range toExpand {
			expandedSteps, err := expandStep(targetStep, expFormula.Template, 0, vars)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Add template steps to the expansion formula
  2. Restore accidentally deleted template steps
  3. Fix the template key/format so steps parse correctly

Example fix

# before
name: fanout
type: expansion
steps: []
# after
name: fanout
type: expansion
steps:
  - id: "${name}-child"
    title: "Child of ${name}"
Defensive patterns

Strategy: validation

Validate before calling

f, err := parser.LoadByName(rule.With)
if err == nil && len(f.Template) == 0 {
    return fmt.Errorf("map rule with=%q: expansion formula has no template steps", rule.With)
}

Type guard

func hasTemplate(f *formula.Formula) bool { return f != nil && f.Type == formula.TypeExpansion && len(f.Template) > 0 }

Try / catch

expanded, err := formula.ApplyExpansions(steps, compose)
if err != nil && strings.Contains(err.Error(), "has no template steps") {
    return fmt.Errorf("empty expansion formula referenced by map rule: %w", err)
}

Prevention

When it happens

Trigger: ApplyExpansions validates each map rule's loaded formula and finds len(expFormula.Template) == 0.

Common situations: Expansion formula file with type: expansion but an empty/missing steps block; template steps removed during refactoring; malformed template key so parsing yields zero steps.

Related errors


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