gastownhall/beads · error
issue %s has status %s, expected one of: %v
Error message
issue %s has status %s, expected one of: %v
What it means
This error is produced by the HasStatus validator when an operation requires the issue to be in one of a specific set of allowed statuses, but the issue's actual Status matches none of them. It reports the current status and the full list of allowed values so the caller can see the mismatch immediately. The library uses it to enforce preconditions like 'issue must be open to be assigned'.
Source
Thrown at internal/validation/issue.go:261
if !force && issue.Status == types.StatusHooked {
return fmt.Errorf("cannot modify hooked issue %s (use --force to override)", id)
}
return nil
}
}
// HasStatus validates that an issue has one of the allowed statuses.
func HasStatus(allowed ...types.Status) IssueValidator {
return func(id string, issue *types.Issue) error {
if issue == nil {
return nil
}
for _, status := range allowed {
if issue.Status == status {
return nil
}
}
return fmt.Errorf("issue %s has status %s, expected one of: %v", id, issue.Status, allowed)
}
}
// HasType validates that an issue has one of the allowed types.
func HasType(allowed ...types.IssueType) IssueValidator {
return func(id string, issue *types.Issue) error {
if issue == nil {
return nil
}
for _, t := range allowed {
if issue.IssueType == t {
return nil
}
}
return fmt.Errorf("issue %s has type %s, expected one of: %v", id, issue.IssueType, allowed)
}
}
View on GitHub (pinned to 71377f2769)
Solutions
- Fetch the issue and check its Status against the expected set before the call, transitioning it if needed
- Broaden or correct the allowed status list passed to HasStatus if the requirement is too strict
- Refresh/re-fetch the issue if your local copy may be stale
- Fix upstream workflow logic that leaves issues in unexpected statuses
Example fix
// before Validate(id, issue, HasStatus(types.StatusOpen)) // fails if in_progress // after Validate(id, issue, HasStatus(types.StatusOpen, types.StatusInProgress))
Defensive patterns
Strategy: validation
Validate before calling
func hasAllowedStatus(issue *types.Issue, allowed ...types.Status) bool {
if issue == nil {
return false
}
for _, s := range allowed {
if issue.Status == s {
return true
}
}
return false
} Type guard
func statusIn(issue *types.Issue, allowed ...types.Status) bool {
return issue != nil && slices.Contains(allowed, issue.Status)
} Try / catch
if err := validate(id, issue); err != nil {
if strings.Contains(err.Error(), "expected one of") {
issue = refresh(id) // re-fetch and re-check before failing
}
return err
} Prevention
- Re-fetch issues before status-sensitive operations instead of using cached data
- Model status transitions explicitly so workflows never assume a stale status
- Keep the allowed-status lists in sync with the library's types after upgrades
- Add pre-flight status checks in bulk scripts with clear skip/report behavior
When it happens
Trigger: Any API call configured with HasStatus(allowed...) on an issue whose issue.Status is not in the allowed slice (e.g. updating an issue expected to be 'open' while it is 'in_progress' or 'closed').
Common situations: Workflow automations assuming a status that a prior step already changed; stale cached issue data where the status moved on; status naming drift after library upgrades changing the allowed set; bulk scripts applying operations to issues in mixed states.
Related errors
- invalid status: %s
- %w: refusing to clear closed_at on %s: its status stays %q,
- %w: refusing to set closed_at on %s: its status stays %q, an
- %w: status value of type %T is neither a string nor a types.
- issue %s has type %s, expected one of: %v
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/2fd5f51e906d817d.
Report an issue: GitHub.