gastownhall/beads · error
duplicate custom status name %q
Error message
duplicate custom status name %q
What it means
When parsing custom statuses (from config or flags), each name is checked against a 'seen' set. If the same name appears twice, validation fails because custom status names must be unique. This prevents ambiguous status semantics downstream.
Source
Thrown at internal/types/types.go:650
category = StatusCategory(catStr)
if !validCategories[category] {
return nil, fmt.Errorf("invalid category %q for status %q: must be one of active, wip, done, frozen", catStr, name)
}
} else {
name = part
category = CategoryUnspecified
}
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 nilView on GitHub (pinned to 71377f2769)
Solutions
- Remove the duplicate entry so each custom status name appears exactly once in the config/flag list
- If merging configs, deduplicate by status name before passing the list to the parser
- Check for JSON/YAML arrays accidentally containing the same object twice
Example fix
// before (config)
"custom_statuses": [{"name":"in-review","category":"progress"},{"name":"in-review","category":"progress"}]
// after
"custom_statuses": [{"name":"in-review","category":"progress"}] Defensive patterns
Strategy: validation
Validate before calling
names := []string{"in-review", "in-review"}
seen := map[string]bool{}
for _, n := range names {
if seen[n] { return fmt.Errorf("duplicate custom status %q", n) }
seen[n] = true
} Type guard
func hasUniqueStatusNames(statuses []CustomStatus) bool {
seen := map[string]bool{}
for _, s := range statuses {
if seen[s.Name] { return false }
seen[s.Name] = true
}
return true
} Try / catch
statuses, err := ParseCustomStatuses(raw)
if errors.Is(err, ErrDuplicateStatus) || strings.Contains(err.Error(), "duplicate custom status") {
// deduplicate and retry
} Prevention
- Deduplicate by name when merging configs from multiple sources
- Add a config linter check for repeated status names
- Keep status definitions in one canonical file
When it happens
Trigger: Calling the custom-status parsing function (types.go, custom status validation) with a list containing two entries with the exact same name after any normalization — e.g. a config file or --status flag listing a status twice.
Common situations: Merging config from multiple sources (user config + project config) where both define the same custom status; copy-pasting a status block; scripted config generation that appends duplicates.
Related errors
- invalid %s value: %v
- server: NewDoltServer: doltBinExec is required
- server: NewDoltServer: rootDir is required
- server: NewDoltServer: configPath is required
- ErrPrefixMismatch
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5d2daa4379e3e4ee.
Report an issue: GitHub.