gastownhall/beads · error
unknown field: %s
Error message
unknown field: %s
What it means
The beads query evaluator only accepts comparison fields from a fixed list (status, priority, type, assignee, owner, label(s), title, description, notes, created/updated/closed/started timestamps, id, spec, parent, pinned, ephemeral, template, mol_type, has_metadata_key, plus any field prefixed with "metadata."). When applyComparison sees a field name outside that set and not a metadata. prefix, it rejects the whole query with this error. It is a query-authoring validation error, not a runtime/storage failure.
Source
Thrown at internal/query/evaluator.go:205
case "spec", "spec_id":
return e.applySpecFilter(comp, filter)
case "parent":
return e.applyParentFilter(comp, filter)
case "pinned":
return e.applyBoolFilter(comp, filter, "pinned")
case "ephemeral":
return e.applyBoolFilter(comp, filter, "ephemeral")
case "template":
return e.applyBoolFilter(comp, filter, "template")
case "mol_type":
return e.applyMolTypeFilter(comp, filter)
case "has_metadata_key":
return e.applyHasMetadataKeyFilter(comp, filter)
default:
if strings.HasPrefix(comp.Field, "metadata.") {
return e.applyMetadataFilter(comp, filter)
}
return fmt.Errorf("unknown field: %s", comp.Field)
}
}
func (e *Evaluator) applyStatusFilter(comp *ComparisonNode, filter *types.IssueFilter) error {
if comp.Op != OpEquals && comp.Op != OpNotEquals {
return fmt.Errorf("status only supports = and != operators")
}
status := types.Status(strings.ToLower(comp.Value))
if !status.IsValid() {
return fmt.Errorf("invalid status: %s", comp.Value)
}
if comp.Op == OpEquals {
filter.Status = &status
} else {
filter.ExcludeStatus = append(filter.ExcludeStatus, status)
}
return nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Check the spelling of the field against the switch in internal/query/evaluator.go:158-200 (applyComparison) and correct it.
- If filtering on a custom metadata entry, prefix the key with "metadata." (e.g. metadata.team = ops) so it routes to applyMetadataFilter.
- If the field genuinely should exist, add a case in applyComparison and a corresponding applyXxxFilter implementation — do not try to work around it client-side.
- Run `bd schema` (or inspect types.IssueFilter) to see which fields are filterable before writing the query.
Example fix
// before (typo'd / unknown field)
filter, err := query.Parse("statues = open")
// after
filter, err := query.Parse("status = open")
// custom metadata field:
// before: "team = ops"
// after: "metadata.team = ops" Defensive patterns
Strategy: validation
Validate before calling
var validFields = map[string]bool{"status":true,"priority":true,"type":true,"assignee":true,"owner":true,"label":true,"labels":true,"title":true,"description":true,"desc":true,"notes":true,"created":true,"created_at":true,"updated":true,"updated_at":true,"closed":true,"closed_at":true,"started":true,"started_at":true,"id":true,"spec":true,"spec_id":true,"parent":true,"pinned":true,"ephemeral":true,"template":true,"mol_type":true,"has_metadata_key":true}
func validQueryField(f string) bool { return validFields[f] || strings.HasPrefix(f, "metadata.") } Type guard
func isComparisonNode(n query.Node) (*query.ComparisonNode, bool) { c, ok := n.(*query.ComparisonNode); return c, ok } Try / catch
if err := evaluator.Apply(node, filter); err != nil {
var qe *query.Error
if errors.As(err, &qe) && strings.HasPrefix(qe.Msg, "unknown field:") {
return fmt.Errorf("query field %q is not filterable; see bd schema", field)
}
return err
} Prevention
- Keep a shared constant list of filterable fields and validate queries against it before evaluation.
- Always prefix custom-field filters with "metadata.".
- Run `bd schema` when unsure which fields exist.
- Write unit tests for every query string shipped in scripts/config.
When it happens
Trigger: Calling the query evaluator (bd list/filter queries) with a ComparisonNode whose Field is not one of the recognized names — e.g. typos like "statues", "priorty", "labels.tags", unquoted arbitrary identifiers like "assignee_email", or a foreign field name from another tool's query language (JQL/SOQL style).
Common situations: Typos in hand-written queries; copying query syntax from GitHub/Jira where fields like "milestone" or "sprint" exist but not in beads; schema drift after renaming a field in a script; assuming custom issue fields are queryable without the required "metadata." prefix.
Related errors
- invalid status: %s
- priority must be between 0 and 4
- graph dependency cycle would be created: %s
- beads directory missing required files: %s
- status only supports = and != operators
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/76175d438204c7e7.
Report an issue: GitHub.