{"record":{"id":"550eaad8e0dcee7f","repo":"gastownhall/beads","slug":"id-with-wildcard-only-supports-and-operators","errorCode":null,"errorMessage":"id with wildcard only supports = and != operators","messagePattern":"id with wildcard only supports = and != operators","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/query/evaluator.go","lineNumber":987,"sourceCode":"\tcase OpGreaterEq:\n\t\treturn actual.After(target) || actual.Equal(target)\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (e *Evaluator) buildIDPredicate(comp *ComparisonNode) (func(*types.Issue) bool, error) {\n\tvalue := comp.Value\n\thasWildcard := strings.HasSuffix(value, \"*\")\n\tif hasWildcard {\n\t\tprefix := strings.TrimSuffix(value, \"*\")\n\t\tswitch comp.Op {\n\t\tcase OpEquals:\n\t\t\treturn func(i *types.Issue) bool { return strings.HasPrefix(i.ID, prefix) }, nil\n\t\tcase OpNotEquals:\n\t\t\treturn func(i *types.Issue) bool { return !strings.HasPrefix(i.ID, prefix) }, nil\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"id with wildcard only supports = and != operators\")\n\t\t}\n\t}\n\tswitch comp.Op {\n\tcase OpEquals:\n\t\treturn func(i *types.Issue) bool { return i.ID == value }, nil\n\tcase OpNotEquals:\n\t\treturn func(i *types.Issue) bool { return i.ID != value }, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"id does not support %s operator\", comp.Op.String())\n\t}\n}\n\nfunc (e *Evaluator) buildSpecPredicate(comp *ComparisonNode) (func(*types.Issue) bool, error) {\n\tvalue := comp.Value\n\thasWildcard := strings.HasSuffix(value, \"*\")\n\tif hasWildcard {\n\t\tprefix := strings.TrimSuffix(value, \"*\")\n\t\tswitch comp.Op {","sourceCodeStart":969,"sourceCodeEnd":1005,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/query/evaluator.go#L969-L1005","documentation":"The id field supports wildcard matching (prefix*) only with the = and != operators. buildIDPredicate returns this error when a wildcard id value is combined with any other comparison operator (>, <, >=, <=, etc.), because ordering a string prefix match is undefined.","triggerScenarios":"A query like `id > bd-1*` or `id <= abc*` — any wildcard-terminated id value used with an operator other than = or !=.","commonSituations":"Copy-pasting a range query pattern from time/numeric fields and applying it to id; trying to express 'starts with' via >=; script generators emitting uniform operator syntax across all fields.","solutions":["Remove the wildcard and use exact match with = or != (e.g. id = bd-123).","Keep the wildcard but switch the operator to = (prefix match) or != (prefix exclusion).","For multiple prefixes, OR separate wildcard equality clauses: id = bd-1* OR id = bd-2*.","Sanitize query builders so wildcard values are only emitted with equality operators."],"exampleFix":"// before\nbd list --query \"id >= bd-1*\"\n// after\nbd list --query \"id = bd-1*\"   // prefix match on all bd-1x ids","handlingStrategy":"validation","validationCode":"func checkIDQuery(field, op, value string) error {\n\tif strings.HasSuffix(value, \"*\") && op != \"=\" && op != \"!=\" {\n\t\treturn fmt.Errorf(\"wildcard %s requires = or !=\", field)\n\t}\n\treturn nil\n}","typeGuard":"func isWildcardIDQuery(op Operator, value string) bool {\n\treturn strings.HasSuffix(value, \"*\") && (op == OpEquals || op == OpNotEquals)\n}","tryCatchPattern":"pred, err := e.Evaluate(q)\nif err != nil {\n\tif strings.Contains(err.Error(), \"only supports = and != operators\") {\n\t\t// rewrite query with = and retry\n\t}\n\treturn err\n}","preventionTips":["Reserve * wildcards for = and != only","Never use ordering operators on id fields","Use OR of exact/prefix matches for id sets","Lint generated queries for wildcard+non-equality combinations"],"tags":["query","operators","wildcard"],"backgroundTag":"unsupported-operator-for-field","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}