gastownhall/beads · error
%q is not a sweep tier; use %q or %q
Error message
%q is not a sweep tier; use %q or %q
What it means
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.
Source
Thrown at internal/workapi/sweep.go:37
// What is NOT here is the sweep itself. Selecting rows and deleting them needs
// one transaction (issueops.Sweeper.Sweep), which no interface above a store
// publishes; the bodies live in internal/storage/issueops/sweep.go and in the
// unit-of-work provider.
// ValidateSweepRequest applies the request rules every Sweeper implementation
// shares, before anything is read.
//
// The require-a-filter refusal for the durable tier is a safety invariant, so
// it lives HERE rather than in a CLI handler: a second front door inherits it
// by calling the role. See issueops.SweepRequest.
func ValidateSweepRequest(in issueops.SweepRequest) error {
switch in.Tier {
case issueops.SweepEphemeral, issueops.SweepDurable:
case "":
return fmt.Errorf("%w: sweep requires a tier (%q or %q), and has no default",
issueops.ErrValidation, issueops.SweepEphemeral, issueops.SweepDurable)
default:
return fmt.Errorf("%w: %q is not a sweep tier; use %q or %q",
issueops.ErrValidation, in.Tier, issueops.SweepEphemeral, issueops.SweepDurable)
}
if in.IDPattern != "" {
// filepath.Match reports a malformed pattern on any subject, so one
// probe against the empty string classifies the pattern itself. The
// front doors used to discard this error, which turned `--pattern '['`
// into "nothing matched" on a command whose job is to delete matches.
if _, err := filepath.Match(in.IDPattern, ""); err != nil {
return fmt.Errorf("%w: --pattern %q is not a valid glob: %v",
issueops.ErrValidation, in.IDPattern, err)
}
}
if in.Tier == issueops.SweepDurable && in.ClosedBefore == nil && in.IDPattern == "" {
return fmt.Errorf("%w: a durable sweep requires a closed-before cutoff or an id pattern; "+
"pass the pattern \"*\" to sweep every closed issue deliberately",
issueops.ErrValidation)
}
return nilView on GitHub (pinned to 71377f2769)
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
Example fix
// before
req := issueops.SweepRequest{Tier: "durable", IDPattern: "bd-*"}
// after
req := issueops.SweepRequest{Tier: issueops.SweepDurable, IDPattern: "bd-*"} Defensive patterns
Strategy: validation
Validate before calling
switch req.Tier {
case issueops.SweepEphemeral, issueops.SweepDurable:
default:
return fmt.Errorf("unknown sweep tier %q", req.Tier)
} Type guard
func isKnownSweepTier(t issueops.SweepTier) bool {
return t == issueops.SweepEphemeral || t == issueops.SweepDurable
} Try / catch
if err := sweeper.Sweep(ctx, req); err != nil {
if errors.Is(err, issueops.ErrValidation) {
return fmt.Errorf("invalid sweep tier: %w", err)
}
return err
} Prevention
- 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
When it happens
Trigger: Calling a Sweeper with issueops.SweepRequest{Tier: "typo"} or any string other than issueops.SweepEphemeral / issueops.SweepDurable / "".
Common situations: 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.
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
- sweep requires a tier (%q or %q), and has no default
- --pattern %q is not a valid glob: %v
- a durable sweep requires a closed-before cutoff or an id pat
- no store is open for this workspace
- not found
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/7ac200b0e64d9222.
Report an issue: GitHub.