gastownhall/beads · error

expand: %q has no template steps

Error message

expand: %q has no template steps

What it means

The `with:` formula in an expand rule is a valid expansion formula, but its template has zero steps. An expansion with no template steps cannot produce any steps, so ApplyExpansions rejects it rather than silently deleting the target step.

Source

Thrown at internal/formula/expand.go:72

			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)
		}

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

		// Expand the target step (start at depth 0)
		expandedSteps, err := expandStep(targetStep, expFormula.Template, 0, vars)
		if err != nil {
			return nil, fmt.Errorf("expand %q: %w", rule.Target, err)
		}

		// Propagate target step's dependencies to root steps of the expansion.
		// Root steps are those whose needs/dependsOn only reference IDs within
		// the expansion (or are empty) — they are the entry points.
		propagateTargetDeps(targetStep, expandedSteps)

		// Replace the target step with expanded steps
		result = replaceStep(result, rule.Target, expandedSteps)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Add template steps to the referenced expansion formula
  2. Restore accidentally removed/commented template steps
  3. Fix the misspelled template key so the steps parse into the formula

Example fix

# before
name: matrix-expand
type: expansion
# steps missing
# after
name: matrix-expand
type: expansion
steps:
  - id: "item-${item}"
    title: "Item ${item}"
Defensive patterns

Strategy: validation

Validate before calling

f, _ := parser.LoadByName(rule.With)
if f.Type == formula.TypeExpansion && len(f.Template) == 0 {
    return fmt.Errorf("expansion formula %q 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("expansion formula %s is empty: %w", rule.With, err)
}

Prevention

When it happens

Trigger: ApplyExpansions encounters an expand rule whose formula passes the TypeExpansion check but has an empty Template slice (no steps defined in the formula file).

Common situations: Formula file defines type: expansion but no steps/template section; steps were commented out or removed during editing; a template YAML/JSON key was misspelled so it parsed to an empty list.

Related errors


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