gastownhall/beads · error
expand: %q is not an expansion formula (type=%s)
Error message
expand: %q is not an expansion formula (type=%s)
What it means
ApplyExpansions loads the expansion formula named by a compose `expand` rule via parser.LoadByName(rule.With). The formula was found and loaded, but its Type is not TypeExpansion (e.g. it is a workflow, aspect, or convoy formula). The library refuses to expand a step with a non-expansion formula because templates/vars semantics only exist for expansion formulas.
Source
Thrown at internal/formula/expand.go:68
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)
}
// 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.View on GitHub (pinned to 71377f2769)
Solutions
- Check the referenced formula's `type:` field in its definition file and change it to `expansion`
- Point the rule's `with:` at the correct expansion formula name
- If the formula should remain a workflow, remove/replace the expand rule instead of expanding with it
Example fix
# before (.formula) with: build-workflow # type: workflow # after with: build-expand # type: expansion
Defensive patterns
Strategy: validation
Validate before calling
f, err := parser.LoadByName(rule.With)
if err != nil { return err }
if f.Type != formula.TypeExpansion {
return fmt.Errorf("rule %q: formula %q must be type expansion, got %s", rule.Target, rule.With, f.Type)
} Type guard
func isExpansionFormula(f *formula.Formula) bool { return f != nil && f.Type == formula.TypeExpansion } Try / catch
expanded, err := formula.ApplyExpansions(steps, compose)
if err != nil {
var notExp *formula.ErrWrongType // or strings.Contains check
if strings.Contains(err.Error(), "is not an expansion formula") {
log.Fatalf("fix `with:` in compose: %v", err)
}
return err
} Prevention
- Keep expansion formulas in a dedicated directory/naming convention (e.g. *-expand) and reference only those
- Validate compose `with:` references in CI before running expansions
- Don't change a formula's type without grepping for its references
When it happens
Trigger: Calling ApplyExpansions with a compose whose Expand rules reference a `with:` formula that exists but is of type workflow/aspect/convoy instead of `expansion`.
Common situations: Typo or copy-paste pointing `with:` at a regular workflow formula; a formula was converted from expansion to another type; reuse of an existing formula name assuming it was an expansion.
Related errors
- applying expansions: %w
- applying expansions to %q: %w
- standalone expansion %q: %w
- expand: target step %q not found
- expand: loading %q: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/eab89f7c88efe575.
Report an issue: GitHub.