gastownhall/beads · error

invalid status: %s

Error message

invalid status: %s

What it means

After checking the operator, applyStatusFilter lowercases the value and validates it via types.Status.IsValid(), which only accepts the built-in statuses: open, in_progress, blocked, deferred, closed, pinned, hooked (types.AllStatuses in internal/types/types.go:521). Any other string — including custom statuses registered via config — is rejected with this error. Note the query path uses the strict built-in-only check, unlike the transaction layer which accepts custom statuses.

Source

Thrown at internal/query/evaluator.go:215

	case "mol_type":
		return e.applyMolTypeFilter(comp, filter)
	case "has_metadata_key":
		return e.applyHasMetadataKeyFilter(comp, filter)
	default:
		if strings.HasPrefix(comp.Field, "metadata.") {
			return e.applyMetadataFilter(comp, filter)
		}
		return fmt.Errorf("unknown field: %s", comp.Field)
	}
}

func (e *Evaluator) applyStatusFilter(comp *ComparisonNode, filter *types.IssueFilter) error {
	if comp.Op != OpEquals && comp.Op != OpNotEquals {
		return fmt.Errorf("status only supports = and != operators")
	}
	status := types.Status(strings.ToLower(comp.Value))
	if !status.IsValid() {
		return fmt.Errorf("invalid status: %s", comp.Value)
	}
	if comp.Op == OpEquals {
		filter.Status = &status
	} else {
		filter.ExcludeStatus = append(filter.ExcludeStatus, status)
	}
	return nil
}

func (e *Evaluator) applyPriorityFilter(comp *ComparisonNode, filter *types.IssueFilter) error {
	priority, err := strconv.Atoi(comp.Value)
	if err != nil {
		return fmt.Errorf("invalid priority value: %s", comp.Value)
	}
	if priority < 0 || priority > 4 {
		return fmt.Errorf("priority must be between 0 and 4")
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Use one of the exact built-in statuses (case-insensitive): open, in_progress, blocked, deferred, closed, pinned, hooked.
  2. If using a custom status, do not query by `status =` — filter on another field or extend the code to use IsValidWithCustom and thread the custom statuses into the evaluator.
  3. Trim whitespace and normalize hyphens to underscores before parsing user input into a query string.
  4. Check `bd schema` for the authoritative status enum.

Example fix

// before
"status = done"
// after
"status = closed"
// before
"status = in-progress"
// after
"status = in_progress"
Defensive patterns

Strategy: validation

Validate before calling

var validStatuses = []string{"open", "in_progress", "blocked", "deferred", "closed", "pinned", "hooked"}
func isValidStatus(s string) bool {
    n := strings.ToLower(strings.TrimSpace(strings.ReplaceAll(s, "-", "_")))
    return slices.Contains(validStatuses, n)
}

Type guard

func toStatus(v string) (types.Status, bool) {
    s := types.Status(strings.ToLower(strings.TrimSpace(v)))
    return s, s.IsValid()
}

Try / catch

if err := e.applyComparison(comp, filter); err != nil {
    if strings.HasPrefix(err.Error(), "invalid status:") {
        return fmt.Errorf("%w (valid: open, in_progress, blocked, deferred, closed, pinned, hooked)", err)
    }
    return err
}

Prevention

When it happens

Trigger: Queries like `status = In-Progress`, `status = done`, `status = wip`, `status = ""`, or using a custom status name defined with `bd config set status.custom ...` — all fail IsValid() and raise this error.

Common situations: Using Jira/GitHub vocabulary (done, wip, review) instead of beads' enum; misremembering "in progress" as "in_progress" vs "in-progress"; expecting custom statuses to work in queries when the evaluator only accepts built-ins; trailing whitespace or capitalization differences (only case is normalized, not hyphens/underscores).

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


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