gastownhall/beads · error

too many custom statuses (%d): maximum is %d

Error message

too many custom statuses (%d): maximum is %d

What it means

The parser enforces a hard cap (maxCustomStatuses) on how many custom statuses can be defined. Exceeding it aborts parsing. The cap keeps status enums, indexes, and UI rendering bounded.

Source

Thrown at internal/types/types.go:658

		if !statusNameRegexp.MatchString(name) {
			return nil, fmt.Errorf("invalid status name %q: must match [a-z][a-z0-9_-]* (lowercase, letter-first, no spaces)", name)
		}

		if builtInStatusNames[strings.ToLower(name)] {
			return nil, fmt.Errorf("custom status %q collides with built-in status", name)
		}

		if seen[name] {
			return nil, fmt.Errorf("duplicate custom status name %q", name)
		}
		seen[name] = true

		result = append(result, CustomStatus{Name: name, Category: category})
	}

	if len(result) > maxCustomStatuses {
		return nil, fmt.Errorf("too many custom statuses (%d): maximum is %d", len(result), maxCustomStatuses)
	}

	return result, nil
}

// CustomStatusNames extracts just the name strings from a slice of CustomStatus.
// Useful for backward-compatible callers that only need names for validation.
func CustomStatusNames(statuses []CustomStatus) []string {
	if len(statuses) == 0 {
		return nil
	}
	names := make([]string, len(statuses))
	for i, s := range statuses {
		names[i] = s.Name
	}
	return names
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Reduce the number of custom statuses to at most maxCustomStatuses
  2. Consolidate near-duplicate statuses (e.g. merge 'in-review-2' into 'in-review')
  3. Split workflows across projects if each genuinely needs its own status set

Example fix

// before
statuses := make([]CustomStatus, 0, 200) // pushes past the cap
// after
if len(statuses) > maxCustomStatuses { statuses = statuses[:maxCustomStatuses] }
Defensive patterns

Strategy: validation

Validate before calling

if len(statuses) > maxCustomStatuses {
    return fmt.Errorf("need at most %d statuses, have %d", maxCustomStatuses, len(statuses))
}

Try / catch

statuses, err := ParseCustomStatuses(raw)
if err != nil && strings.Contains(err.Error(), "too many custom statuses") {
    // trim/merge statuses before retrying
}

Prevention

When it happens

Trigger: Supplying more than maxCustomStatuses entries in the custom statuses list passed to the parsing function in types.go.

Common situations: Bulk-importing statuses from another tracker; generated config with a status per team or per workflow stage; looping scripts that append statuses without checking the total.

Related errors


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