{"record":{"id":"236de5e421aca80b","repo":"gastownhall/beads","slug":"invalid-sort-policy-s-valid-values-hybrid-pr","errorCode":null,"errorMessage":"invalid sort policy '%s'. Valid values: hybrid, priority, oldest","messagePattern":"invalid sort policy '(.+?)'\\. Valid values: hybrid, priority, oldest","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/workapi/ready.go","lineNumber":100,"sourceCode":"\t}\n\tif len(in.MetadataFields) > 0 {\n\t\tfilter.MetadataFields = in.MetadataFields\n\t}\n\n\tif err := ValidateMetadataFilters(in.MetadataFields, in.HasMetadataKey); err != nil {\n\t\treturn filter, err\n\t}\n\n\tif !filter.SortPolicy.IsValid() {\n\t\t// A deterministic request-validation failure, so it matches\n\t\t// ErrValidation: every role whose filter vocabulary this builds —\n\t\t// Reader.Ready, ReadyClaimer.ClaimNext and BatchCloser's ClaimNext —\n\t\t// promises a caller can classify one with errors.Is rather than by\n\t\t// reading prose. The wrap is %.0w rather than a \"%w: \" prefix because\n\t\t// this text is what `bd ready --sort bogus` prints verbatim behind\n\t\t// \"Error: \"; prefixing it would change user-visible copy to say\n\t\t// something the reader already knows.\n\t\treturn filter, fmt.Errorf(\"invalid sort policy '%s'. Valid values: hybrid, priority, oldest%.0w\", in.Sort, issueops.ErrValidation)\n\t}\n\treturn filter, nil\n}\n\n// BuildReadyCountFilter turns a ready request into the storage-level filter a\n// COUNT of the ready set runs against: BuildReadyFilter's filter with the page\n// removed, and the single definition of what `bd ready`'s published total means.\n//\n// It refuses a request carrying a page. issueops.ReadyCounter.CountReady\n// promises its answer equals len(Reader.Ready(r with Limit=0).Items), and a\n// Limit would make that \"how many of the first N\" while an Offset would\n// subtract the rows it skipped from the size of a set that still holds them.\n//\n// The zeroed limit is set on a LOCAL copy: a nil Limit means the shared ready\n// default at BuildReadyFilter, so an unlimited count has to say so explicitly.\nfunc BuildReadyCountFilter(in issueops.ReadyRequest) (types.WorkFilter, error) {\n\tif in.Limit != nil {\n\t\treturn types.WorkFilter{}, fmt.Errorf(\"%w: a ready count does not take a limit\", issueops.ErrValidation)","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/workapi/ready.go#L82-L118","documentation":"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.","triggerScenarios":"Calling BuildReadyFilter with issueops.ReadyRequest.Sort set to anything other than \"\", \"hybrid\", \"priority\", or \"oldest\" — e.g. `bd ready --sort bogus`.","commonSituations":"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.","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"],"exampleFix":"// before\nbd ready --sort newest\n// after\nbd ready --sort oldest","handlingStrategy":"validation","validationCode":"var validSorts = map[string]bool{\"hybrid\": true, \"priority\": true, \"oldest\": true}\nif in.Sort != \"\" && !validSorts[in.Sort] {\n\treturn fmt.Errorf(\"sort must be one of hybrid, priority, oldest\")\n}","typeGuard":null,"tryCatchPattern":"filter, err := BuildReadyFilter(req)\nif err != nil && errors.Is(err, issueops.ErrValidation) && strings.Contains(err.Error(), \"invalid sort policy\") {\n\t// reject the flag value; message is user-facing verbatim\n}","preventionTips":["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"],"tags":["cli","validation","sorting","ready-queue"],"backgroundTag":"invalid-enum-value","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}