{"record":{"id":"17bfb806a99a7f5b","repo":"gastownhall/beads","slug":"invalid-end-expression-w","errorCode":null,"errorMessage":"invalid end expression: %w","messagePattern":"invalid end expression: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/range.go","lineNumber":377,"sourceCode":"\n\t// Check that expressions parse (with placeholder vars)\n\tplaceholderVars := make(map[string]string)\n\trangeVarPattern.ReplaceAllStringFunc(expr, func(match string) string {\n\t\tname := match[1 : len(match)-1]\n\t\tplaceholderVars[name] = \"1\" // Use 1 as placeholder\n\t\treturn \"1\"\n\t})\n\n\tstartExpr := strings.TrimSpace(m[1])\n\tstartExpr = substituteVars(startExpr, placeholderVars)\n\tif _, err := tokenize(startExpr); err != nil {\n\t\treturn fmt.Errorf(\"invalid start expression: %w\", err)\n\t}\n\n\tendExpr := strings.TrimSpace(m[2])\n\tendExpr = substituteVars(endExpr, placeholderVars)\n\tif _, err := tokenize(endExpr); err != nil {\n\t\treturn fmt.Errorf(\"invalid end expression: %w\", err)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":359,"sourceCodeEnd":382,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/range.go#L359-L382","documentation":"ValidateRange parses a range expression like {{range i=START..END}} and checks both bound expressions. This error wraps a tokenize() failure on the end (right-hand) expression, meaning the end bound is not syntactically valid token stream. It follows a successful start-expression check, so only the end bound is at fault.","triggerScenarios":"Calling ValidateRange (directly or via validateLoopSpec) with a range spec whose end expression, after variable substitution, fails tokenize(): unbalanced parentheses/braces, stray operators, or an empty end expression.","commonSituations":"Formula authors typo the range end (e.g. `..}` or `..items]`), reference a variable that substitutes to an empty/invalid string, or use template syntax that the tokenizer does not accept.","solutions":["Print the end expression after substituteVars to see exactly what the tokenizer rejects.","Fix the end bound to a valid expression (literal integer or valid variable reference).","Ensure the placeholder variable used in the end expression is defined in placeholderVars and substitutes to a non-empty value.","Run tokenize() on the end expression yourself in a quick script to confirm it parses before validating the whole formula."],"exampleFix":"// before\n{{range i=0..}}\n// after\n{{range i=0..9}}","handlingStrategy":"validation","validationCode":"endExpr := strings.TrimSpace(m[2])\nif endExpr == \"\" {\n    return fmt.Errorf(\"range end expression is empty\")\n}\nif _, err := tokenize(endExpr); err != nil {\n    return fmt.Errorf(\"range end %q invalid: %v\", endExpr, err)\n}","typeGuard":null,"tryCatchPattern":"var verr *ValidationError\nif errors.As(err, &verr) && strings.Contains(err.Error(), \"invalid end expression\") { /* fix formula range syntax */ }","preventionTips":["Always write explicit, non-empty range ends (e.g. `..9`).","Check that variables used in range bounds substitute to valid integer strings.","Lint formula range expressions in CI with ValidateRange before shipping."],"tags":["formula","range-validation","tokenize"],"backgroundTag":"invalid-expression-syntax","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}