gastownhall/beads · error
metadata fields only support = operator
Error message
metadata fields only support = operator
What it means
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.
Source
Thrown at internal/query/evaluator.go:502
return nil
}
func (e *Evaluator) applyMolTypeFilter(comp *ComparisonNode, filter *types.IssueFilter) error {
if comp.Op != OpEquals {
return fmt.Errorf("mol_type only supports = operator")
}
mt := types.MolType(strings.ToLower(comp.Value))
if !mt.IsValid() {
return fmt.Errorf("invalid mol_type: %s", comp.Value)
}
filter.MolType = &mt
return nil
}
// applyMetadataFilter handles metadata.<key>=<value> queries (GH#1406).
func (e *Evaluator) applyMetadataFilter(comp *ComparisonNode, filter *types.IssueFilter) error {
if comp.Op != OpEquals {
return fmt.Errorf("metadata fields only support = operator")
}
key := strings.TrimPrefix(comp.Field, "metadata.")
if err := storage.ValidateMetadataKey(key); err != nil {
return err
}
if filter.MetadataFields == nil {
filter.MetadataFields = make(map[string]string)
}
filter.MetadataFields[key] = comp.Value
return nil
}
// applyHasMetadataKeyFilter handles has_metadata_key=<keyname> queries (GH#1406).
func (e *Evaluator) applyHasMetadataKeyFilter(comp *ComparisonNode, filter *types.IssueFilter) error {
if comp.Op != OpEquals {
return fmt.Errorf("has_metadata_key only supports = operator")
}
if err := storage.ValidateMetadataKey(comp.Value); err != nil {View on GitHub (pinned to 71377f2769)
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>`
Example fix
// before bd list 'metadata.team!=core' // after bd list 'metadata.team=core' # only = is supported for metadata fields
Defensive patterns
Strategy: validation
Validate before calling
// validate metadata query shape before running
var metadataEq = regexp.MustCompile(`^metadata\.[A-Za-z0-9_-]+\s*=\s*\S+$`)
if !metadataEq.MatchString(clause) {
return fmt.Errorf("metadata filter must be metadata.<key>=<value>")
} Type guard
func isMetadataEquals(field, op string) bool {
return strings.HasPrefix(field, "metadata.") && op == "="
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- has_metadata_key only supports = operator
- ExternalDoltConfig: must set Socket or (Host, Port)
- ErrQuery
- metadata must be a JSON object: %w
- metadata.repo: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/dbcb66ba8c989cdd.
Report an issue: GitHub.