{"record":{"id":"a698976f24a2fb1a","repo":"gastownhall/beads","slug":"evaluating-range-end-q-w","errorCode":null,"errorMessage":"evaluating range end %q: %w","messagePattern":"evaluating range end %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/range.go","lineNumber":66,"sourceCode":"\t// Parse start..end format\n\tm := rangePattern.FindStringSubmatch(expr)\n\tif m == nil {\n\t\treturn nil, fmt.Errorf(\"invalid range format %q: expected start..end\", expr)\n\t}\n\n\tstartExpr := strings.TrimSpace(m[1])\n\tendExpr := strings.TrimSpace(m[2])\n\n\t// Evaluate start expression\n\tstart, err := EvaluateExpr(startExpr, vars)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"evaluating range start %q: %w\", startExpr, err)\n\t}\n\n\t// Evaluate end expression\n\tend, err := EvaluateExpr(endExpr, vars)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"evaluating range end %q: %w\", endExpr, err)\n\t}\n\n\treturn &RangeSpec{Start: start, End: end}, nil\n}\n\n// EvaluateExpr evaluates a mathematical expression with variable substitution.\n// Supports: + - * / ^ (power) and parentheses.\n// Variables use {name} syntax.\nfunc EvaluateExpr(expr string, vars map[string]string) (int, error) {\n\t// Substitute variables first\n\texpr = substituteVars(expr, vars)\n\n\t// Tokenize and parse\n\ttokens, err := tokenize(expr)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/range.go#L48-L84","documentation":"ParseRange() evaluated the start side fine but EvaluateExpr failed on the end expression, so the end side of the range is not a valid arithmetic expression after variable substitution. The failing end expression and the evaluator's cause are wrapped in the error.","triggerScenarios":"ParseRange(\"1..b\", vars) with 'b' undefined; end expressions containing unsupported operators or non-numeric residue; unexpanded placeholders like \"1..2^{k}\" where k is absent from vars; expandLoopWithVars passing a partially-substituted end expression.","commonSituations":"Count-driven loops ('1..{count}') where the count var was never set or was set to a non-numeric string like 'auto'; typos in the end-side variable name; copy-paste leaving currency symbols or whitespace tokens in the expression.","solutions":["Fix the end expression to valid arithmetic, e.g. \"1..10\" or \"1..2^{n}\".","Ensure the variables referenced on the end side are present in the vars map and numeric after substitution.","Inspect the inner EvaluateExpr error to pinpoint whether it is an unknown variable or invalid token."],"exampleFix":"# before\nrange: \"1..{count}\"   # count = \"auto\"\n\n# after\nvars: { count: \"10\" }\nrange: \"1..{count}\"","handlingStrategy":"validation","validationCode":"// Check that every {var} in the end expression exists and is numeric.\nfor _, m := range varRefRe.FindAllStringSubmatch(endExpr, -1) {\n\tv, ok := vars[m[1]]\n\tif !ok {\n\t\treturn fmt.Errorf\"undefined var %q in range end\", m[1]\n\t}\n\tif _, err := strconv.Atoi(strings.TrimSpace(v)); err != nil {\n\t\treturn fmt.Errorf\"var %q=%q is not numeric\", m[1], v\n\t}\n}","typeGuard":null,"tryCatchPattern":"spec, err := ParseRange(expr, vars)\nif err != nil {\n\tif strings.Contains(err.Error(), \"evaluating range end\") {\n\t\t// fix the end expression or the vars it references\n\t}\n}","preventionTips":["Coerce count-like vars to integers before they are substituted into ranges.","Reject non-numeric values at config load time for vars used in range ends.","Cover count-driven loops in tests with both present and absent count vars."],"tags":["go","range","expression-evaluation","variables"],"backgroundTag":"invalid-range-format","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}