{"record":{"id":"aa324c0d15159e99","repo":"gastownhall/beads","slug":"spec-with-wildcard-only-supports-and-operator","errorCode":null,"errorMessage":"spec with wildcard only supports = and != operators","messagePattern":"spec with wildcard only supports = and != operators","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/query/evaluator.go","lineNumber":1011,"sourceCode":"\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 {\n\t\tcase OpEquals:\n\t\t\treturn func(i *types.Issue) bool { return strings.HasPrefix(i.SpecID, prefix) }, nil\n\t\tcase OpNotEquals:\n\t\t\treturn func(i *types.Issue) bool { return !strings.HasPrefix(i.SpecID, prefix) }, nil\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"spec 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.SpecID == value }, nil\n\tcase OpNotEquals:\n\t\treturn func(i *types.Issue) bool { return i.SpecID != value }, nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"spec does not support %s operator\", comp.Op.String())\n\t}\n}\n\nfunc (e *Evaluator) buildBoolPredicate(comp *ComparisonNode, getter func(*types.Issue) bool) (func(*types.Issue) bool, error) {\n\tval := strings.ToLower(comp.Value)\n\tvar boolVal bool\n\tswitch val {\n\tcase \"true\", \"yes\", \"1\":\n\t\tboolVal = true","sourceCodeStart":993,"sourceCodeEnd":1029,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/query/evaluator.go#L993-L1029","documentation":"The spec field supports wildcard (prefix*) matching only with = and !=. buildSpecPredicate returns this error when a wildcard spec value is combined with any other operator, mirroring the id-field rule: prefix matching has no ordering semantics.","triggerScenarios":"A query like `spec > auth*` or `spec <= obs*` — wildcard-terminated spec id with a non-equality operator, reaching buildComparisonPredicate.","commonSituations":"Reusing range-query syntax across fields; mistaking spec for a sortable field; generated queries from dashboards or scripts that append operators uniformly.","solutions":["Switch to spec = prefix* for prefix match or spec != prefix* for exclusion.","Drop the wildcard for an exact spec match: spec = bd-123.","Combine multiple prefix matches with OR clauses.","Constrain any programmatic query emitter to equality operators for spec."],"exampleFix":"// before\nbd list --query \"spec >= auth*\"\n// after\nbd list --query \"spec = auth*\"","handlingStrategy":"validation","validationCode":"func checkSpecQuery(op Operator, value string) error {\n\tif strings.HasSuffix(value, \"*\") && op != OpEquals && op != OpNotEquals {\n\t\treturn fmt.Errorf(\"spec wildcard requires = or !=\")\n\t}\n\treturn nil\n}","typeGuard":"func isWildcardSpecQuery(op Operator, value string) bool {\n\treturn strings.HasSuffix(value, \"*\") && (op == OpEquals || op == OpNotEquals)\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"spec with wildcard only supports\") {\n\treturn fmt.Errorf(\"use spec = prefix* or spec != prefix*: %w\", err)\n}","preventionTips":["Only pair wildcard spec values with = or !=","Use exact spec ids for other filtering needs","Validate operator/value pairing before emitting the query","Keep spec query syntax mirrored with id query syntax in tooling"],"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"}