gastownhall/beads · error
loop %q: %w
Error message
loop %q: %w
What it means
expandLoopWithVars parses the step's Loop.Range with ParseRange using the provided template variables and wraps any parse failure. This is the variable-substitution range path: the range string is expanded with vars before parsing, and if the resulting spec is unparseable the loop expansion aborts.
Source
Thrown at internal/formula/controlflow.go:146
}
// Recursively expand any nested loops FIRST
var err error
result, err = ApplyLoops(result)
if err != nil {
return nil, err
}
// THEN chain iterations on the expanded result
// This must happen AFTER recursive expansion so we chain the final steps
if step.Loop.Count > 1 {
result = chainExpandedIterations(result, step.ID, step.Loop.Count)
}
} else if step.Loop.Range != "" {
// Range loop: expand body for each value in the computed range
rangeSpec, err := ParseRange(step.Loop.Range, vars)
if err != nil {
return nil, fmt.Errorf("loop %q: %w", step.ID, err)
}
// Validate range
if rangeSpec.End < rangeSpec.Start {
return nil, fmt.Errorf("loop %q: range end (%d) is less than start (%d)",
step.ID, rangeSpec.End, rangeSpec.Start)
}
// Expand body for each value in range
count := rangeSpec.End - rangeSpec.Start + 1
iterNum := 0
for val := rangeSpec.Start; val <= rangeSpec.End; val++ {
iterNum++
// Build iteration vars: include the loop variable if specified
iterVars := make(map[string]string)
if step.Loop.Var != "" {
iterVars[step.Loop.Var] = fmt.Sprintf("%d", val)
}View on GitHub (pinned to 71377f2769)
Solutions
- Ensure every variable used in the range expression is present in the vars map and resolves to an integer
- Print/log the substituted range string to see what ParseRange actually received
- Fix the range syntax in the formula definition
- Use validateLoopSpec/ApplyLoops preflight to catch malformed ranges before expansion
Example fix
// before
expandLoop(step, map[string]string{"start": "one"}) // range: "{{start}}..3"
// after
expandLoop(step, map[string]string{"start": "1"}) Defensive patterns
Strategy: validation
Validate before calling
func checkRangeVars(r string, vars map[string]string) error {
for _, m := range regexp.MustCompile(`\{\{(\w+)\}\}`).FindAllStringSubmatch(r, -1) {
if _, ok := vars[m[1]]; !ok {
return fmt.Errorf("range %q: missing variable %q", r, m[1])
}
}
return nil
} Try / catch
expanded, err := expandLoops(steps, vars)
if err != nil {
if strings.Contains(err.Error(), "loop \"") {
return fmt.Errorf("range loop failed to parse; check vars resolve to integers: %w", err)
}
return err
} Prevention
- Ensure every variable referenced in a range is supplied in the vars map
- Verify variable values are numeric strings before expansion
- Log the substituted range string when debugging expansion failures
When it happens
Trigger: expandLoop (called during formula expansion with variables) seeing a Loop.Range that, after variable substitution, still fails ParseRange — e.g. unresolved `{{var}}` placeholders or malformed bounds.
Common situations: A variable referenced in the range was not provided in the vars map, so `{{n}}` remains literal; a variable resolves to a non-numeric string; typo in the range separator after substitution.
Related errors
- loop %q: invalid range %q: %w
- loop %q: range end (%d) is less than start (%d)
- loop %q: max must be positive
- loop %q: invalid until condition %q: %w
- applying control flow: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/505141f4b531e54c.
Report an issue: GitHub.