{"record":{"id":"dbcb66ba8c989cdd","repo":"gastownhall/beads","slug":"metadata-fields-only-support-operator","errorCode":null,"errorMessage":"metadata fields only support = operator","messagePattern":"metadata fields only support = operator","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/query/evaluator.go","lineNumber":502,"sourceCode":"\treturn nil\n}\n\nfunc (e *Evaluator) applyMolTypeFilter(comp *ComparisonNode, filter *types.IssueFilter) error {\n\tif comp.Op != OpEquals {\n\t\treturn fmt.Errorf(\"mol_type only supports = operator\")\n\t}\n\tmt := types.MolType(strings.ToLower(comp.Value))\n\tif !mt.IsValid() {\n\t\treturn fmt.Errorf(\"invalid mol_type: %s\", comp.Value)\n\t}\n\tfilter.MolType = &mt\n\treturn nil\n}\n\n// applyMetadataFilter handles metadata.<key>=<value> queries (GH#1406).\nfunc (e *Evaluator) applyMetadataFilter(comp *ComparisonNode, filter *types.IssueFilter) error {\n\tif comp.Op != OpEquals {\n\t\treturn fmt.Errorf(\"metadata fields only support = operator\")\n\t}\n\tkey := strings.TrimPrefix(comp.Field, \"metadata.\")\n\tif err := storage.ValidateMetadataKey(key); err != nil {\n\t\treturn err\n\t}\n\tif filter.MetadataFields == nil {\n\t\tfilter.MetadataFields = make(map[string]string)\n\t}\n\tfilter.MetadataFields[key] = comp.Value\n\treturn nil\n}\n\n// applyHasMetadataKeyFilter handles has_metadata_key=<keyname> queries (GH#1406).\nfunc (e *Evaluator) applyHasMetadataKeyFilter(comp *ComparisonNode, filter *types.IssueFilter) error {\n\tif comp.Op != OpEquals {\n\t\treturn fmt.Errorf(\"has_metadata_key only supports = operator\")\n\t}\n\tif err := storage.ValidateMetadataKey(comp.Value); err != nil {","sourceCodeStart":484,"sourceCodeEnd":520,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/query/evaluator.go#L484-L520","documentation":"The beads query engine's metadata.<key> fields (GH#1406) are only implemented for exact equality matching. applyMetadataFilter runs in filter mode (AND-style filters pushed to IssueFilter.MetadataFields); any other comparison operator (!=, =~, >, IN, etc.) is rejected with this error. It exists because metadata filtering maps to a storage-level field filter that has no semantics for other operators.","triggerScenarios":"Running a bd query like `metadata.team!=core`, `metadata.team=~cor`, or `metadata.priority>2` — any metadata.<key> comparison whose Op is not OpEquals, dispatched via applyComparison to applyMetadataFilter.","commonSituations":"Users assume metadata fields behave like regular fields and try negation, regex, or range matching; queries written by analogy with type/status fields which do support more operators; OR-query authors hit the sibling error at buildMetadataPredicate (index 2142) instead.","solutions":["Rewrite the comparison to use the = operator, e.g. `metadata.team=core` instead of `metadata.team!=core`","If you need negation, invert the logic: fetch with metadata.team=core and exclude those results, or use NOT (NOT is also limited to = in filter mode)","If you need richer matching, filter in a post-processing step over the JSON metadata of returned issues","Validate metadata keys are non-empty with storage.ValidateMetadataKey semantics; a malformed key yields a different error, but keep the query shape `metadata.<key>=<scalar>`"],"exampleFix":"// before\nbd list 'metadata.team!=core'\n// after\nbd list 'metadata.team=core'  # only = is supported for metadata fields","handlingStrategy":"validation","validationCode":"// validate metadata query shape before running\nvar metadataEq = regexp.MustCompile(`^metadata\\.[A-Za-z0-9_-]+\\s*=\\s*\\S+$`)\nif !metadataEq.MatchString(clause) {\n    return fmt.Errorf(\"metadata filter must be metadata.<key>=<value>\")\n}","typeGuard":"func isMetadataEquals(field, op string) bool {\n    return strings.HasPrefix(field, \"metadata.\") && op == \"=\"\n}","tryCatchPattern":null,"preventionTips":["Only use = with metadata.<key> fields","Never negate or regex-match metadata in queries; post-filter instead","Validate keys are non-empty and simple identifiers","Remember the restriction applies in both AND (filter) and OR (predicate) modes"],"tags":["query","metadata","operator-not-supported"],"backgroundTag":"query-operator-not-supported","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}