{"record":{"id":"ff6310c66642ddf4","repo":"gastownhall/beads","slug":"invalid-range-format-q-expected-start-end","errorCode":null,"errorMessage":"invalid range format %q: expected start..end","messagePattern":"invalid range format %q: expected start\\.\\.end","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/range.go","lineNumber":51,"sourceCode":"\n// ParseRange parses a range expression and evaluates it using the given variables.\n// Returns the start and end values of the range.\n//\n// Examples:\n//\n//\tParseRange(\"1..10\", nil)           -> {1, 10}\n//\tParseRange(\"1..2^3\", nil)          -> {1, 8}\n//\tParseRange(\"1..2^{n}\", {\"n\":\"3\"})  -> {1, 8}\nfunc ParseRange(expr string, vars map[string]string) (*RangeSpec, error) {\n\texpr = strings.TrimSpace(expr)\n\tif expr == \"\" {\n\t\treturn nil, fmt.Errorf(\"empty range expression\")\n\t}\n\n\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","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/range.go#L33-L69","documentation":"ParseRange() matched the trimmed expression against rangePattern (start..end) and it did not match, so the expression is not a valid 'start..end' range. The offending expression is quoted in the error.","triggerScenarios":"Calling ParseRange(\"1-10\", vars), ParseRange(\"1 to 10\", vars), ParseRange(\"..5\", vars) or any expression lacking the literal '..' separator with parseable start and end sides; expandLoopWithVars passing a malformed range string from a molecule.","commonSituations":"Using a single '-' or '...' instead of '..'; copying range syntax from another language (Python's range(1,10) or Ruby's 1..10 written as 1,10); template placeholders not fully expanded leaving stray braces that break the regex.","solutions":["Rewrite the expression in start..end form with the double-dot separator, e.g. \"1..10\".","Check for unexpanded template variables in the string and ensure the vars map supplies them.","Validate the range string (regex ^[^.]+\\.\\.[^.]+$ style check) before passing it to ParseRange."],"exampleFix":"# before\nrange: \"1-10\"\n\n# after\nrange: \"1..10\"","handlingStrategy":"validation","validationCode":"var rangeRe = regexp.MustCompile(`^[^.]+\\.\\.[^.]+$`)\nif !rangeRe.MatchString(strings.TrimSpace(rawRange)) {\n\treturn fmt.Errorf(\"range %q must be start..end\", rawRange)\n}","typeGuard":null,"tryCatchPattern":"spec, err := ParseRange(expr, vars)\nif err != nil {\n\tif strings.Contains(err.Error(), \"expected start..end\") {\n\t\t// show the correct syntax next to the bad value\n\t}\n}","preventionTips":["Always use the double-dot separator; do not port range syntax from other languages.","Lint molecule frontmatter for range fields against the start..end pattern.","Ensure template placeholders are fully expanded before the string reaches ParseRange."],"tags":["go","range","parsing","syntax"],"backgroundTag":"invalid-range-format","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}