{"record":{"id":"4eb0f781485a5d98","repo":"gastownhall/beads","slug":"loop-q-invalid-range-q-w","errorCode":null,"errorMessage":"loop %q: invalid range %q: %w","messagePattern":"loop %q: invalid range %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/controlflow.go","lineNumber":103,"sourceCode":"\tif loop.Count < 0 {\n\t\treturn fmt.Errorf(\"loop %q: count must be positive\", stepID)\n\t}\n\n\tif loop.Max < 0 {\n\t\treturn fmt.Errorf(\"loop %q: max must be positive\", stepID)\n\t}\n\n\t// Validate until condition syntax if present\n\tif loop.Until != \"\" {\n\t\tif _, err := ParseCondition(loop.Until); err != nil {\n\t\t\treturn fmt.Errorf(\"loop %q: invalid until condition %q: %w\", stepID, loop.Until, err)\n\t\t}\n\t}\n\n\t// Validate range syntax if present\n\tif loop.Range != \"\" {\n\t\tif err := ValidateRange(loop.Range); err != nil {\n\t\t\treturn fmt.Errorf(\"loop %q: invalid range %q: %w\", stepID, loop.Range, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// expandLoop expands a loop step into its constituent steps.\nfunc expandLoop(step *Step) ([]*Step, error) {\n\treturn expandLoopWithVars(step, nil)\n}\n\n// expandLoopWithVars expands a loop step using the given variable context.\n// The vars map is used to resolve range expressions with variables.\nfunc expandLoopWithVars(step *Step, vars map[string]string) ([]*Step, error) {\n\tvar result []*Step\n\n\tif step.Loop.Count > 0 {\n\t\t// Fixed-count loop: expand body N times","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/controlflow.go#L85-L121","documentation":"validateLoopSpec validates the loop's Range expression with ValidateRange and wraps any failure. Range loops iterate over a start..end spec; a malformed spec cannot be expanded, so ApplyLoops rejects it up front.","triggerScenarios":"ApplyLoops encountering a LoopSpec whose Range is non-empty but fails ValidateRange (e.g. not of the form 'start..end', non-numeric bounds, reversed bounds at syntax level, extra characters).","commonSituations":"Writing `range: 1-5` instead of the expected `1..5` separator; leaving spaces or stray characters; unresolved template variables leaving literal `{{x}}` in the range string (use range-with-vars expansion path instead).","solutions":["Fix the range string to match ValidateRange's accepted format (e.g. `start..end`)","Check for typos or extra whitespace/characters in the range value","If the range depends on variables, ensure the vars-expansion path parses it correctly via ParseRange"],"exampleFix":"# before\nloop:\n  range: \"1-5\"\n# after\nloop:\n  range: \"1..5\"","handlingStrategy":"validation","validationCode":"func validateLoopRange(r string) error {\n\tif r == \"\" {\n\t\treturn nil\n\t}\n\treturn formula.ValidateRange(r)\n}","typeGuard":null,"tryCatchPattern":"steps, err := formula.ApplyLoops(steps)\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid range\") {\n\t\treturn fmt.Errorf(\"check loop.range syntax (expected start..end): %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Use the documented range separator (e.g. `..`) consistently","Run ValidateRange on all range strings before applying formulas","Avoid embedding unresolved template placeholders in static ranges"],"tags":["go","formula","validation","range","loops"],"backgroundTag":"invalid-range-expression","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}