{"record":{"id":"1e4a074775e66214","repo":"gastownhall/beads","slug":"empty-query","errorCode":null,"errorMessage":"empty query","messagePattern":"empty query","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/query/parser.go","lineNumber":110,"sourceCode":"type Parser struct {\n\tlexer   *Lexer\n\tcurrent Token\n\tpeeked  *Token\n}\n\n// NewParser creates a new Parser for the given input.\nfunc NewParser(input string) *Parser {\n\treturn &Parser{lexer: NewLexer(input)}\n}\n\n// Parse parses the query string and returns the root AST node.\nfunc (p *Parser) Parse() (Node, error) {\n\tif err := p.advance(); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif p.current.Type == TokenEOF {\n\t\treturn nil, fmt.Errorf(\"empty query\")\n\t}\n\n\tnode, err := p.parseOr()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif p.current.Type != TokenEOF {\n\t\treturn nil, fmt.Errorf(\"unexpected token %q at position %d (expected end of query)\", p.current.Value, p.current.Pos)\n\t}\n\n\treturn node, nil\n}\n\n// advance moves to the next token.\nfunc (p *Parser) advance() error {\n\tif p.peeked != nil {\n\t\tp.current = *p.peeked","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/query/parser.go#L92-L128","documentation":"Parser.Parse (internal/query/parser.go:110) found TokenEOF as the very first token, meaning the input query string was empty or contained only whitespace. The grammar requires at least one comparison or expression, so an empty query is rejected rather than returning a match-all node.","triggerScenarios":"query.Parse(\"\") or query.Parse(\"   \"); a shell variable holding the query expanding to nothing (`bd list --query \"$Q\"` with Q unset); passing `--query \"\"` on the CLI; programmatic callers building a query from optional parts that all evaluated to empty.","commonSituations":"Unset or empty environment variables in scripts; CI configs with a blank query field; string builders that only append clauses inside conditionals and produce \"\" when no condition matched.","solutions":["Provide a non-empty query, e.g. `status=open`.","Guard the call site: if the query string is blank after TrimSpace, skip the query API entirely instead of parsing.","In shell, use `${Q:?Q not set}` or default the query (`${Q:-status=open}`) before passing it.","When building queries programmatically, default to a catch-all known field clause when no parts were added."],"exampleFix":"// before\nnode, err := query.Parse(userQuery) // \"\" -> error\n// after\nif strings.TrimSpace(userQuery) == \"\" {\n    return nil // or default query\n}\nnode, err := query.Parse(userQuery)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(q) == \"\" {\n    return nil // skip query entirely or use a default\n}","typeGuard":null,"tryCatchPattern":"node, err := query.Parse(q)\nif err != nil && err.Error() == \"empty query\" {\n    return handleAll() // treat as no filter\n}","preventionTips":["TrimSpace the query and short-circuit before calling Parse","In shell scripts use ${Q:?msg} to fail fast on unset query variables","Default optional query builders to a known clause like status=open when empty","Validate CLI/config query fields at load time"],"tags":["query-language","parser","empty-input"],"backgroundTag":"empty-query-input","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}