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

  1. Fetch the issue and check its Status against the expected set before the call, transitioning it if needed
  2. Broaden or correct the allowed status list passed to HasStatus if the requirement is too strict
  3. Refresh/re-fetch the issue if your local copy may be stale
  4. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/2fd5f51e906d817d. Report an issue: GitHub.