gastownhall/beads · error
invalid sort policy '%s'. Valid values: hybrid, priority, ol
Error message
invalid sort policy '%s'. Valid values: hybrid, priority, oldest
What it means
BuildReadyFilter rejects an unrecognized --sort policy with 'invalid sort policy ... Valid values: hybrid, priority, oldest', wrapping issueops.ErrValidation with %.0w so the message prints verbatim behind 'Error: ' without a prefix. The promise is that callers classify it with errors.Is rather than string matching.
Source
Thrown at internal/workapi/ready.go:100
}
if len(in.MetadataFields) > 0 {
filter.MetadataFields = in.MetadataFields
}
if err := ValidateMetadataFilters(in.MetadataFields, in.HasMetadataKey); err != nil {
return filter, err
}
if !filter.SortPolicy.IsValid() {
// A deterministic request-validation failure, so it matches
// ErrValidation: every role whose filter vocabulary this builds —
// Reader.Ready, ReadyClaimer.ClaimNext and BatchCloser's ClaimNext —
// promises a caller can classify one with errors.Is rather than by
// reading prose. The wrap is %.0w rather than a "%w: " prefix because
// this text is what `bd ready --sort bogus` prints verbatim behind
// "Error: "; prefixing it would change user-visible copy to say
// something the reader already knows.
return filter, fmt.Errorf("invalid sort policy '%s'. Valid values: hybrid, priority, oldest%.0w", in.Sort, issueops.ErrValidation)
}
return filter, nil
}
// BuildReadyCountFilter turns a ready request into the storage-level filter a
// COUNT of the ready set runs against: BuildReadyFilter's filter with the page
// removed, and the single definition of what `bd ready`'s published total means.
//
// It refuses a request carrying a page. issueops.ReadyCounter.CountReady
// promises its answer equals len(Reader.Ready(r with Limit=0).Items), and a
// Limit would make that "how many of the first N" while an Offset would
// subtract the rows it skipped from the size of a set that still holds them.
//
// The zeroed limit is set on a LOCAL copy: a nil Limit means the shared ready
// default at BuildReadyFilter, so an unlimited count has to say so explicitly.
func BuildReadyCountFilter(in issueops.ReadyRequest) (types.WorkFilter, error) {
if in.Limit != nil {
return types.WorkFilter{}, fmt.Errorf("%w: a ready count does not take a limit", issueops.ErrValidation)View on GitHub (pinned to 71377f2769)
Solutions
- Use exactly one of hybrid, priority, or oldest (or leave empty for the default)
- Check errors.Is(err, issueops.ErrValidation) to classify the refusal programmatically
- If a new policy is genuinely needed, file/extend the filter rather than passing arbitrary strings
Example fix
// before bd ready --sort newest // after bd ready --sort oldest
Defensive patterns
Strategy: validation
Validate before calling
var validSorts = map[string]bool{"hybrid": true, "priority": true, "oldest": true}
if in.Sort != "" && !validSorts[in.Sort] {
return fmt.Errorf("sort must be one of hybrid, priority, oldest")
} Try / catch
filter, err := BuildReadyFilter(req)
if err != nil && errors.Is(err, issueops.ErrValidation) && strings.Contains(err.Error(), "invalid sort policy") {
// reject the flag value; message is user-facing verbatim
} Prevention
- Only pass hybrid, priority, oldest, or empty for --sort
- Keep sort values as constants, not free-form strings
- Update scripts when the sort vocabulary changes
When it happens
Trigger: Calling BuildReadyFilter with issueops.ReadyRequest.Sort set to anything other than "", "hybrid", "priority", or "oldest" — e.g. `bd ready --sort bogus`.
Common situations: Typo'd or abbreviated sort names ('prio', 'hyb'); scripts written against an older sort vocabulary; config files carrying a sort value from a fork with extra policies.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- got %d close reasons for %d issue IDs; provide exactly one s
- cannot specify both --reason-file and --reason/--resolution/
- --reason-file %q is empty; close reason is required
- invalid mode '%s', must be 'compile' or 'runtime'
- runtime mode requires all variables to have values Missing:
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/236de5e421aca80b.
Report an issue: GitHub.