gastownhall/beads · error
inline expand on step %q: %w
Error message
inline expand on step %q: %w
What it means
Wrapper error thrown when expandStep fails while instantiating a step's inline expansion template with merged variables. expandStep performs placeholder substitution ({target.title}, variable refs, repeat logic); any failure there (missing required variable, bad placeholder, invalid repeat spec) is re-wrapped with the offending step ID. The root cause is preserved via %w.
Source
Thrown at internal/formula/expand.go:490
return nil, fmt.Errorf("inline expand on step %q: loading %q: %w", step.ID, step.Expand, err)
}
if expFormula.Type != TypeExpansion {
return nil, fmt.Errorf("inline expand on step %q: %q is not an expansion formula (type=%s)",
step.ID, step.Expand, expFormula.Type)
}
if len(expFormula.Template) == 0 {
return nil, fmt.Errorf("inline expand on step %q: %q has no template steps", step.ID, step.Expand)
}
// Merge formula default vars with step's ExpandVars overrides
vars := mergeVars(expFormula, step.ExpandVars)
// Expand the step using the template (reuse existing expandStep)
expandedSteps, err := expandStep(step, expFormula.Template, 0, vars)
if err != nil {
return nil, fmt.Errorf("inline expand on step %q: %w", step.ID, err)
}
// Propagate the original step's dependencies to root steps of the expansion
propagateTargetDeps(step, expandedSteps)
// Recursively process expanded steps for nested inline expansions
processedSteps, err := applyInlineExpansionsRecursive(expandedSteps, parser, depth+1)
if err != nil {
return nil, err
}
result = append(result, processedSteps...)
} else {
// No inline expansion - keep the step, but process children recursively
clone := cloneStep(step)
if len(step.Children) > 0 {
processedChildren, err := applyInlineExpansionsRecursive(step.Children, parser, depth)View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped inner error to identify the failing placeholder or variable.
- Add the missing key to the step's ExpandVars or set it as a default var in the expansion formula.
- Fix malformed placeholder syntax in the template (e.g. {target.title} vs a typo like {traget.title}).
- Validate the formula/template locally by running it through bd before wiring it into a larger workflow.
Example fix
// before
[[step]]
id = "scaffold"
expand = "scaffolding"
# template needs {project.name} but no vars given
// after
[[step]]
id = "scaffold"
expand = "scaffolding"
[step.expandvars]
project_name = "my-app" Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check that template vars are satisfiable: defaults + ExpandVars cover placeholders used
vars := map[string]string{}
for k, v := range expFormula.Vars {
vars[k] = v
}
for k, v := range step.ExpandVars {
vars[k] = v
}
for _, t := range expFormula.Template {
for _, ph := range placeholderNames(t) { // scan {var.x} tokens
if _, ok := vars[ph]; !ok {
return fmt.Errorf("step %q: template needs var %q", step.ID, ph)
}
}
} Try / catch
expanded, err := formula.ApplyInlineExpansions(steps, parser)
if err != nil {
if strings.Contains(err.Error(), "inline expand on step") {
return fmt.Errorf("expanding %s: %w", stepID, err) // surface inner cause to user
}
return err
} Prevention
- Provide ExpandVars for every variable the template references, or set defaults in the formula.
- Keep placeholder names simple and consistent ({target.title}, {var.name}) and review template edits.
- Run formulas through a dry-run/expansion test before wiring them into workflows.
When it happens
Trigger: ApplyInlineExpansions calls expandStep(step, expFormula.Template, 0, vars) and the template references variables not provided by the formula defaults nor the step's ExpandVars, or contains malformed placeholders/repeat directives.
Common situations: Step omits an ExpandVars entry the template requires; placeholder name typo in the template; template uses iteration variables outside a repeat context; formula defaults removed in a newer formula version.
Related errors
- inline expand on step %q: %q has no template steps
- standalone expansion %q: %w
- formula %q not accessible: %w
- ensureProxiedServerConfig: render YAML: %w
- loop %q: max must be positive
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/40f7e1506dc4e25d.
Report an issue: GitHub.