gastownhall/beads · error
expected digit at position %d
Error message
expected digit at position %d
What it means
A token starting with '-' or '+' was not followed by a digit. readNumberOrDuration (internal/query/lexer.go:253) only treats sign-led tokens as numbers/durations, so '-' or '+' followed by an identifier character (e.g. `-alpha`) is rejected. Unsigned digit-led runs with identifier continuations are tolerated (re-lexed as identifiers), but signed forms must be numeric.
Source
Thrown at internal/query/lexer.go:253
// they can stand in unquoted on the value side of comparisons like
// "label=1-alpha". Signed forms ("-3-foo") still error — the user has
// to quote them.
func (l *Lexer) readNumberOrDuration(startPos int) (Token, error) {
var sb strings.Builder
// Handle optional sign
r := l.next()
hadSign := r == '-' || r == '+'
if hadSign {
sb.WriteRune(r)
r = l.next()
}
// Must have at least one digit
if !unicode.IsDigit(r) {
l.backup()
// This might be a minus in front of an identifier, which is invalid
return Token{}, fmt.Errorf("expected digit at position %d", l.pos)
}
sb.WriteRune(r)
// Read remaining digits
for {
r = l.next()
if !unicode.IsDigit(r) {
break
}
sb.WriteRune(r)
}
// Check for duration suffix. Only commit to a duration when the suffix
// stands alone — if more identifier characters follow (e.g. "7day"),
// fall through to the identifier-fallback below.
if r != 0 && isDurationSuffix(r) && !isIdentChar(l.peek()) {
sb.WriteRune(r)
return Token{Type: TokenDuration, Value: sb.String(), Pos: startPos}, nilView on GitHub (pinned to 71377f2769)
Solutions
- Quote sign-led values: `label="-alpha"` (comment in lexer.go confirms signed forms must be quoted).
- If you meant exclusion, there is no `-` exclusion operator — use `NOT label=foo`.
- If the value is hyphenated but starts with a digit (e.g. `1-alpha`), it is already accepted unquoted; only leading signs need quoting.
- Check the reported position: it points just past the sign, where a digit was expected.
Example fix
// before
query.Parse("label=-alpha")
// after
query.Parse("label=\"-alpha\"") Defensive patterns
Strategy: validation
Validate before calling
// Quote sign-led values before parsing
func quoteSignedValues(q string) string {
return regexp.MustCompile(`(=|!=|<|<=|>|>=)\s*([+-][A-Za-z_][\w./:-]*)`).ReplaceAllString(q, "$1\"$2\"")
} Try / catch
if _, err := query.Parse(q); err != nil && strings.Contains(err.Error(), "expected digit") {
return fmt.Errorf("values starting with - or + must be quoted: %w", err)
} Prevention
- Quote any value that starts with '-' or '+'
- Remember unsigned digit-led values (1-alpha, 42d-sla) are fine unquoted
- Use NOT field=value for exclusion — there is no leading-minus exclusion syntax
- Run the sign-quoting sanitizer on user-supplied queries
When it happens
Trigger: query.Parse with a sign-led non-numeric value: `label=-alpha`, `status=-new`, `priority=+high`, `assignee=-me`, or a negated bare word like `NOT -foo=1`.
Common situations: Users writing shell-style `-flag` prefixes inside queries; values that legitimately begin with '-' (hyphenated labels like `-experimental`) supplied unquoted; minus used to mean exclusion (`-label=foo`) as in other search DSLs.
Related errors
- unexpected character '!' at position %d (did you mean '!=' o
- unexpected character %q at position %d
- unterminated string starting at position %d
- unterminated escape sequence at position %d
- closed does not support %s operator
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/40ae36c8c32d119d.
Report an issue: GitHub.