gastownhall/beads · error
expected comparison operator at position %d, got %s
Error message
expected comparison operator at position %d, got %s
What it means
After reading a field name, parseComparison (internal/query/parser.go:267) expects one of the six comparison operators (=, !=, <, <=, >, >=). Any other token type — an identifier, string, number, EOF, AND/OR/NOT, or paren — produces this error. The common case is a field name immediately followed by a value with no operator between them.
Source
Thrown at internal/query/parser.go:267
return nil, err
}
var op ComparisonOp
switch p.current.Type {
case TokenEquals:
op = OpEquals
case TokenNotEquals:
op = OpNotEquals
case TokenLess:
op = OpLess
case TokenLessEq:
op = OpLessEq
case TokenGreater:
op = OpGreater
case TokenGreaterEq:
op = OpGreaterEq
default:
return nil, fmt.Errorf("expected comparison operator at position %d, got %s", p.current.Pos, p.current.Type.String())
}
if err := p.advance(); err != nil {
return nil, err
}
// Value can be identifier, string, number, or duration
var value string
var valueType TokenType
switch p.current.Type {
case TokenIdent:
value = p.current.Value
valueType = TokenIdent
case TokenString:
value = p.current.Value
valueType = TokenString
case TokenNumber:
value = p.current.ValueView on GitHub (pinned to 71377f2769)
Solutions
- Insert an explicit comparison operator: `status=open` instead of `status open`.
- Replace `:` with `=` — colon is not an operator in this grammar (it is legal inside identifiers/label values only).
- For existence-style intent, write a boolean comparison: `has_metadata_key=true` or `assignee!=""` style forms.
- Remove SQL keywords (IS, IN, LIKE) which are not operators here; use =, !=, <, <=, >, >= only.
Example fix
// before
query.Parse("status open")
// after
query.Parse("status=open") Defensive patterns
Strategy: validation
Validate before calling
var opRe = regexp.MustCompile(`(!?=|<=?|>=?)`)
func hasOperator(field, rest string) bool {
return opRe.MatchString(rest)
} Try / catch
if _, err := query.Parse(q); err != nil && strings.Contains(err.Error(), "expected comparison operator") {
return fmt.Errorf("use =, !=, <, <=, > or >= between field and value: %w", err)
} Prevention
- Always place one of =, !=, <, <=, >, >= between field and value
- Do not use Lucene/SQL syntax (:, IS, IN, LIKE, ~) — only the six operators exist
- For existence checks write explicit comparisons like has_metadata_key=true
- Lint queries for a bare `field value` pattern before parsing
When it happens
Trigger: query.Parse with `status open` (space instead of =), `status:"open"` (colon is not an operator), `status~open` (tilde unsupported), `status =` followed by EOF then the error fires on EOF... actually the operator slot receives TokenIdent in `status open`, TokenString in `status "open"`, TokenEOF in `status` alone.
Common situations: Users typing SQL-style `status IS open` or `field:value` syntax (Lucene/GitHub habit); dropping the `=` during editing; bare field names intended as existence checks (`has_metadata_key` alone) — existence-style fields must still be given a comparison, e.g. `has_metadata_key=true`.
Related errors
- empty query
- unexpected token %q at position %d (expected end of query)
- expected ')' at position %d, got %s
- expected field name at position %d, got %s
- unexpected token after expression
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/56f278570a87a84c.
Report an issue: GitHub.