gastownhall/beads · error
invalid number %q
Error message
invalid number %q
What it means
tokenize() scans a numeric literal in a range expression and hands the slice to strconv.ParseFloat. If the slice cannot be parsed as a float64 (e.g. multiple dots like '1.2.3'), the tokenizer fails with this error. It is the low-level lexical validation of number literals in range start/end expressions.
Source
Thrown at internal/formula/range.go:149
for i < len(expr) {
ch := expr[i]
// Skip whitespace
if unicode.IsSpace(rune(ch)) {
i++
continue
}
// Number
if unicode.IsDigit(rune(ch)) {
j := i
for j < len(expr) && (unicode.IsDigit(rune(expr[j])) || expr[j] == '.') {
j++
}
val, err := strconv.ParseFloat(expr[i:j], 64)
if err != nil {
return nil, fmt.Errorf("invalid number %q", expr[i:j])
}
tokens = append(tokens, token{tokNumber, val})
i = j
continue
}
// Operators
switch ch {
case '+':
tokens = append(tokens, token{tokPlus, 0})
case '-':
// Could be unary minus or subtraction
// If previous token is not a number or right paren, it's unary
if len(tokens) == 0 || (tokens[len(tokens)-1].typ != tokNumber && tokens[len(tokens)-1].typ != tokRParen) {
// Unary minus: parse the number with the minus
j := i + 1
for j < len(expr) && (unicode.IsDigit(rune(expr[j])) || expr[j] == '.') {
j++View on GitHub (pinned to 71377f2769)
Solutions
- Fix the numeric literal so it has at most one decimal point (e.g. '1.2..10')
- Run ValidateRange on the expression before evaluation to get the same diagnostic early
- If the value comes from a variable, check the substituted value is a plain number
Example fix
// before
range 1.2.3..10 { ... }
// after
range 1.23..10 { ... } Defensive patterns
Strategy: validation
Validate before calling
re := /^[0-9]+(\.[0-9]+)?$/
for _, part := range strings.Split(expr, "..") {
// after variable substitution, each numeric literal should match
_ = re
}
ValidateRange(expr) // run before EvaluateExpr to surface this early Try / catch
tokens, err := tokenize(expr)
if err != nil && strings.Contains(err.Error(), "invalid number") {
// fall back to a default range or report a user-facing config error
} Prevention
- Run ValidateRange on every range expression before evaluation
- Never build numeric literals by string concatenation of user input
- Reject values with more than one '.' during config load
When it happens
Trigger: Calling EvaluateExpr or ValidateRange with an expression containing a malformed numeric literal that the digit/dot scan captures, such as '1.2.3..10' — the scan grabs '1.2.3' (digits and dots) and ParseFloat rejects it.
Common situations: Typos in loop specs like '..' inside a number, pasted expressions with thousands separators ('1,000' won't scan here but '1.0.0' will), or template placeholders that expand into malformed numbers.
Related errors
- unexpected character %q in expression
- parsing formula: %w
- parsing JSON: %w
- unexpected token after expression
- unexpected token in expression
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/8bbf561eb7f55bea.
Report an issue: GitHub.