{"record":{"id":"a388b2c2cf66fe86","repo":"gastownhall/beads","slug":"type-only-supports-and-operators","errorCode":null,"errorMessage":"type only supports = and != operators","messagePattern":"type only supports = and != operators","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/query/evaluator.go","lineNumber":264,"sourceCode":"\t\tfilter.PriorityMax = &max\n\tcase OpLessEq:\n\t\tfilter.PriorityMax = &priority\n\tcase OpGreater:\n\t\t// priority > X means PriorityMin = X+1\n\t\tmin := priority + 1\n\t\tif min > 4 {\n\t\t\treturn fmt.Errorf(\"priority > %d matches nothing\", priority)\n\t\t}\n\t\tfilter.PriorityMin = &min\n\tcase OpGreaterEq:\n\t\tfilter.PriorityMin = &priority\n\t}\n\treturn nil\n}\n\nfunc (e *Evaluator) applyTypeFilter(comp *ComparisonNode, filter *types.IssueFilter) error {\n\tif comp.Op != OpEquals && comp.Op != OpNotEquals {\n\t\treturn fmt.Errorf(\"type only supports = and != operators\")\n\t}\n\tissueType := types.IssueType(strings.ToLower(comp.Value))\n\tif comp.Op == OpEquals {\n\t\tfilter.IssueType = &issueType\n\t} else {\n\t\tfilter.ExcludeTypes = append(filter.ExcludeTypes, issueType)\n\t}\n\treturn nil\n}\n\nfunc (e *Evaluator) applyAssigneeFilter(comp *ComparisonNode, filter *types.IssueFilter) error {\n\tif comp.Op != OpEquals {\n\t\treturn fmt.Errorf(\"assignee only supports = operator\")\n\t}\n\tif comp.Value == \"\" || strings.ToLower(comp.Value) == \"none\" || strings.ToLower(comp.Value) == \"null\" {\n\t\tfilter.NoAssignee = true\n\t} else {\n\t\tfilter.Assignee = &comp.Value","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/query/evaluator.go#L246-L282","documentation":"Like status, the type field only supports equality operators. applyTypeFilter rejects any ComparisonNode with Field=\"type\" whose operator is not = or !=. Unlike status, there is no value validation here — any string is accepted as an IssueType and simply won't match unknown types in results.","triggerScenarios":"Queries like `type > bug`, `type <= feature`, `type ~ task` — Field=\"type\" with Op other than OpEquals/OpNotEquals.","commonSituations":"SQL habits (`type LIKE ...`); generic query builders that default every field to an ordering operator; confusion between the `type` field and free-text search which does support substring matching.","solutions":["Rewrite with = or != : e.g. `type = bug`.","To match multiple types, issue one query per type or use the Go API setting IssueFilter.ExcludeTypes for exclusion.","For fuzzy matching, use the text search fields (title/description) instead of type."],"exampleFix":"// before\n\"type >= bug\"\n// after\n\"type = bug\"","handlingStrategy":"validation","validationCode":"func validateTypeOp(op query.Op) error {\n    if op != query.OpEquals && op != query.OpNotEquals {\n        return fmt.Errorf(\"type supports only = and !=, got %v\", op)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := e.applyComparison(comp, filter); err != nil {\n    if strings.Contains(err.Error(), \"type only supports\") {\n        return rewriteWithEquals(comp)\n    }\n    return err\n}","preventionTips":["Never use LIKE/substring semantics on enum fields; use title/description search for fuzzy matching.","Validate generated queries against a per-field operator whitelist.","Check `bd schema` for valid type values since applyTypeFilter does not validate the value itself."],"tags":["query","type","operator","beads"],"backgroundTag":"unsupported-query-operator","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}