gastownhall/beads · error
materializing expansion %q: %w
Error message
materializing expansion %q: %w
What it means
MaterializeExpansion builds concrete steps for an expansion formula by calling expandStep with depth 0 and the merged vars. If expandStep fails (depth limit or substitution error), the error is wrapped with the formula name for context.
Source
Thrown at internal/formula/expand.go:433
// This enables expansion formulas to be directly instantiated via wisp/pour
// without requiring a Compose wrapper (bd-qzb).
//
// No-op if the formula is not an expansion type, has no Template, or already
// has Steps.
func MaterializeExpansion(f *Formula, targetID string, vars map[string]string) error {
if f.Type != TypeExpansion || len(f.Template) == 0 || len(f.Steps) > 0 {
return nil
}
target := &Step{
ID: targetID,
Title: f.Formula,
Description: f.Description,
}
expandedSteps, err := expandStep(target, f.Template, 0, vars)
if err != nil {
return fmt.Errorf("materializing expansion %q: %w", f.Formula, err)
}
f.Steps = expandedSteps
return nil
}
// ApplyInlineExpansions applies Step.Expand fields to inline expansions.
// Steps with the Expand field set are replaced by the referenced expansion template.
// The step's ExpandVars are passed as variable overrides to the expansion.
//
// This differs from compose.Expand in that the expansion is declared inline on the
// step itself rather than in a central compose section.
//
// Returns a new steps slice with inline expansions applied.
// The original steps slice is not modified.
func ApplyInlineExpansions(steps []*Step, parser *Parser) ([]*Step, error) {
if parser == nil {
return steps, nilView on GitHub (pinned to 71377f2769)
Solutions
- Check the wrapped inner error for the root cause
- Define all template variables as defaults in the expansion formula or pass them via vars
- Remove recursive inline expansions from the template
Example fix
# before: uses ${env} but env undefined
steps:
- id: "run-${env}"
# after
vars:
env: dev
steps:
- id: "run-${env}" Defensive patterns
Strategy: try-catch
Validate before calling
for _, v := range requiredVars(f.Template) { // scan {var} placeholders
if _, ok := vars[v]; !ok { return fmt.Errorf("missing var %q for formula %q", v, f.Formula) }
} Type guard
func hasAllVars(f *formula.Formula, vars map[string]string) bool {
for _, name := range templateVarNames(f.Template) {
if _, ok := vars[name]; !ok { return false }
}
return true
} Try / catch
if err := formula.MaterializeExpansion(f); err != nil {
if strings.Contains(err.Error(), "depth limit") {
return fmt.Errorf("formula %s expansion too deep: %w", f.Formula, err)
}
return err
} Prevention
- Define defaults for every variable a template uses
- Avoid inline self-expansion inside templates
- Unit-test MaterializeExpansion for each expansion formula
When it happens
Trigger: Calling MaterializeExpansion on a formula whose template causes expandStep to fail — e.g. template placeholders referencing variables absent from f.Vars, or (via inline expansion) recursion pushing depth past 5.
Common situations: Materializing a formula with missing variable defaults; templates that inline-expand into themselves; partially edited templates with broken {var} references.
Related errors
- invalid variable format '%s', expected 'key=value'
- applying expansions: %w
- runtime mode requires all variables to have values Missing:
- formula %q: %w
- applying expansions to %q: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/34544b6e9681e4a4.
Report an issue: GitHub.