gastownhall/beads · error
unexpected token in expression
Error message
unexpected token in expression
What it means
parsePrimary's default branch fires when the current token cannot start an operand — it is not a number, variable, or '('. This catches expressions beginning with an operator or containing a dangling operator where an operand is expected.
Source
Thrown at internal/formula/range.go:343
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 {
return fmt.Errorf("invalid range format: expected start..end")
}
// Check that expressions parse (with placeholder vars)
placeholderVars := make(map[string]string)View on GitHub (pinned to 71377f2769)
Solutions
- Ensure every operator has a left and right operand
- Fix the expression so it starts with a number, variable, or '('
- Validate with ValidateRange before evaluating
Example fix
// before
range 1..*3 { ... }
// after
range 1..(2*3) { ... } Defensive patterns
Strategy: validation
Validate before calling
// reject expressions starting with a binary operator
leading := regexp.MustCompile(`^\s*[*/^]`)
if leading.MatchString(expr) { /* reject */ } Try / catch
val, err := EvaluateExpr(expr, vars)
if err != nil && strings.Contains(err.Error(), "unexpected token in expression") {
// treat as malformed user input; no retry
} Prevention
- Ensure variable substitution never yields an empty operand
- Start expressions with a number, variable, or '(' only
- Validate with ValidateRange before evaluation
When it happens
Trigger: EvaluateExpr with expressions like 'range 1..*3', '1..+5' where '+5' at operand position is fine but '*3' is not, or a variable pattern that tokenized unexpectedly leaving an operator at operand position.
Common situations: Binary operator typo at expression start ('*2..10'), variables expanding to nothing so an operator becomes the leading token, precedence mistakes in generated expressions.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- unexpected token after expression
- unexpected character %q in expression
- expected closing parenthesis
- parsing formula: %w
- parsing JSON: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/394a45033daf1e10.
Report an issue: GitHub.