gastownhall/beads · error
has_metadata_key only supports = operator
Error message
has_metadata_key only supports = operator
What it means
has_metadata_key tests for the existence of a metadata key and is implemented only as exact equality with a key name. applyHasMetadataKeyFilter runs in filter mode; any operator other than = is rejected. Existence testing has no meaningful != / =~ semantics in the storage filter, so the engine fails fast.
Source
Thrown at internal/query/evaluator.go:518
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 {
return err
}
filter.HasMetadataKey = comp.Value
return nil
}
// buildMetadataPredicate builds a predicate for metadata.<key>=<value> in OR queries.
// Parses the issue's JSON metadata and compares the top-level scalar at the given key.
func (e *Evaluator) buildMetadataPredicate(comp *ComparisonNode) (func(*types.Issue) bool, error) {
if comp.Op != OpEquals {
return nil, fmt.Errorf("metadata fields only support = operator")
}
key := strings.TrimPrefix(comp.Field, "metadata.")
if err := storage.ValidateMetadataKey(key); err != nil {
return nil, err
}View on GitHub (pinned to 71377f2769)
Solutions
- Use `has_metadata_key=team` — the only supported form
- To find issues missing a key, list issues with has_metadata_key=team and exclude them client-side (there is no NOT support for has_metadata_key in filter mode)
- In OR/predicate mode the equivalent restriction applies (see buildHasMetadataKeyPredicate); keep the same = form there
- Match the key name exactly as stored; keys are validated by storage.ValidateMetadataKey
Example fix
// before bd list 'has_metadata_key!=team' // after bd list 'has_metadata_key=team'
Defensive patterns
Strategy: validation
Validate before calling
if field == "has_metadata_key" && op != "=" {
return fmt.Errorf("has_metadata_key requires = (got %s)", op)
} Type guard
func isHasMetadataKeyEquals(field, op string) bool {
return field == "has_metadata_key" && op == "="
} Prevention
- Always write has_metadata_key=<keyname>
- Do not attempt != or prefix matching on key names
- For 'key absent' checks, exclude matched results client-side
- Use exact stored key names
When it happens
Trigger: A query like `has_metadata_key!=team` or `has_metadata_key=~te` dispatched from applyComparison to applyHasMetadataKeyFilter with comp.Op != OpEquals.
Common situations: Trying to express 'issues missing key X' with !=; attempting wildcard/prefix key matching; copy-pasting operator styles from other query languages (SQL IS NULL / IS NOT NULL analogies).
Related errors
- metadata fields only support = 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/207d29affe8aff0b.
Report an issue: GitHub.