gastownhall/beads · error
expected closing parenthesis
Error message
expected closing parenthesis
What it means
parsePrimary handles parenthesized sub-expressions: after parsing the inner expression it requires a ')' token. If the next token is not a closing parenthesis, the parentheses are unbalanced or malformed and this error is thrown.
Source
Thrown at internal/formula/range.go:338
}
return p.parsePrimary()
}
// parsePrimary handles numbers and parentheses
func (p *exprParser) parsePrimary() (float64, error) {
switch p.current().typ {
case tokNumber:
val := p.current().val
p.advance()
return val, nil
case tokLParen:
p.advance()
val, err := p.parseAddSub()
if err != nil {
return 0, err
}
if p.current().typ != tokRParen {
return 0, fmt.Errorf("expected closing parenthesis")
}
p.advance()
return val, nil
default:
return 0, fmt.Errorf("unexpected token in expression")
}
}
// ValidateRange validates a range expression without evaluating it.
// Useful for syntax checking during formula validation.
func ValidateRange(expr string) error {
expr = strings.TrimSpace(expr)
if expr == "" {
return fmt.Errorf("empty range expression")
}
m := rangePattern.FindStringSubmatch(expr)
if m == nil {View on GitHub (pinned to 71377f2769)
Solutions
- Balance the parentheses in the expression (add the missing ')')
- Count opening/closing parens programmatically before evaluation
- Syntax-check with ValidateRange first
Example fix
// before
range 1..(2+3 { ... }
// after
range 1..(2+3) { ... } Defensive patterns
Strategy: validation
Validate before calling
func parensBalanced(s string) bool {
n := 0
for _, r := range s {
if r == '(' { n++ }
if r == ')' { n--; if n < 0 { return false } }
}
return n == 0
}
// call before EvaluateExpr Try / catch
val, err := EvaluateExpr(expr, vars)
if err != nil && strings.Contains(err.Error(), "expected closing parenthesis") {
// surface a friendly 'unbalanced parentheses' message
} Prevention
- Check parenthesis balance before evaluation
- When generating expressions, emit parens as matched pairs
- Run ValidateRange as a pre-flight check
When it happens
Trigger: EvaluateExpr with an unclosed parenthesis, e.g. 'range 1..(2+3' — after parsing '2+3' the parser sees EOF instead of ')'.
Common situations: Hand-edited formulas losing a ')', template expansion dropping characters, nested parens miscounted in generated expressions.
Related errors
- unexpected token after expression
- unexpected token in expression
- unexpected character %q in expression
- division by zero
- invalid range format: expected start..end
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/c93a6c22aaa9ce3d.
Report an issue: GitHub.