{"record":{"id":"7ac200b0e64d9222","repo":"gastownhall/beads","slug":"q-is-not-a-sweep-tier-use-q-or-q","errorCode":null,"errorMessage":"%q is not a sweep tier; use %q or %q","messagePattern":"%q is not a sweep tier; use %q or %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/workapi/sweep.go","lineNumber":37,"sourceCode":"// What is NOT here is the sweep itself. Selecting rows and deleting them needs\n// one transaction (issueops.Sweeper.Sweep), which no interface above a store\n// publishes; the bodies live in internal/storage/issueops/sweep.go and in the\n// unit-of-work provider.\n\n// ValidateSweepRequest applies the request rules every Sweeper implementation\n// shares, before anything is read.\n//\n// The require-a-filter refusal for the durable tier is a safety invariant, so\n// it lives HERE rather than in a CLI handler: a second front door inherits it\n// by calling the role. See issueops.SweepRequest.\nfunc ValidateSweepRequest(in issueops.SweepRequest) error {\n\tswitch in.Tier {\n\tcase issueops.SweepEphemeral, issueops.SweepDurable:\n\tcase \"\":\n\t\treturn fmt.Errorf(\"%w: sweep requires a tier (%q or %q), and has no default\",\n\t\t\tissueops.ErrValidation, issueops.SweepEphemeral, issueops.SweepDurable)\n\tdefault:\n\t\treturn fmt.Errorf(\"%w: %q is not a sweep tier; use %q or %q\",\n\t\t\tissueops.ErrValidation, in.Tier, issueops.SweepEphemeral, issueops.SweepDurable)\n\t}\n\tif in.IDPattern != \"\" {\n\t\t// filepath.Match reports a malformed pattern on any subject, so one\n\t\t// probe against the empty string classifies the pattern itself. The\n\t\t// front doors used to discard this error, which turned `--pattern '['`\n\t\t// into \"nothing matched\" on a command whose job is to delete matches.\n\t\tif _, err := filepath.Match(in.IDPattern, \"\"); err != nil {\n\t\t\treturn fmt.Errorf(\"%w: --pattern %q is not a valid glob: %v\",\n\t\t\t\tissueops.ErrValidation, in.IDPattern, err)\n\t\t}\n\t}\n\tif in.Tier == issueops.SweepDurable && in.ClosedBefore == nil && in.IDPattern == \"\" {\n\t\treturn fmt.Errorf(\"%w: a durable sweep requires a closed-before cutoff or an id pattern; \"+\n\t\t\t\"pass the pattern \\\"*\\\" to sweep every closed issue deliberately\",\n\t\t\tissueops.ErrValidation)\n\t}\n\treturn nil","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/workapi/sweep.go#L19-L55","documentation":"ValidateSweepRequest refuses a Tier value that is neither empty nor one of the two known tiers (SweepEphemeral, SweepDurable). Unknown tier strings indicate a typo or a stale caller, and since the tier controls what a sweep may delete, the validator rejects anything outside the vocabulary with this message naming the valid options.","triggerScenarios":"Calling a Sweeper with issueops.SweepRequest{Tier: \"typo\"} or any string other than issueops.SweepEphemeral / issueops.SweepDurable / \"\".","commonSituations":"A flag value like \"durable \" (trailing space) or \"Durable\" (wrong case) slipped through; a caller hand-wrote the tier string instead of using the exported constants; a renamed constant left old code passing a retired value.","solutions":["Use the exported constants issueops.SweepEphemeral / issueops.SweepDurable instead of string literals","Normalize/trim user-supplied tier values before building the request","Handle errors.Is(err, issueops.ErrValidation) and echo the two accepted tiers"],"exampleFix":"// before\nreq := issueops.SweepRequest{Tier: \"durable\", IDPattern: \"bd-*\"}\n// after\nreq := issueops.SweepRequest{Tier: issueops.SweepDurable, IDPattern: \"bd-*\"}","handlingStrategy":"validation","validationCode":"switch req.Tier {\ncase issueops.SweepEphemeral, issueops.SweepDurable:\ndefault:\n    return fmt.Errorf(\"unknown sweep tier %q\", req.Tier)\n}","typeGuard":"func isKnownSweepTier(t issueops.SweepTier) bool {\n    return t == issueops.SweepEphemeral || t == issueops.SweepDurable\n}","tryCatchPattern":"if err := sweeper.Sweep(ctx, req); err != nil {\n    if errors.Is(err, issueops.ErrValidation) {\n        return fmt.Errorf(\"invalid sweep tier: %w\", err)\n    }\n    return err\n}","preventionTips":["Use the exported tier constants everywhere; forbid raw string literals in review","Normalize and trim user-supplied tier values before assignment","Add an exhaustive switch (with a default that errors) wherever tiers are handled"],"tags":["go","validation","sweep","enum-value"],"backgroundTag":"invalid-enum-value","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}