gastownhall/beads · error
add label: id must not be empty
Error message
add label: id must not be empty
What it means
A guard error from the label use case's internal add(): it rejects adding a label when the target issue/wisp ID is the empty string. Called by AddLabel and AddWispLabel before any repository write happens, so nothing is persisted.
Source
Thrown at internal/storage/domain/label.go:61
}
type labelUseCaseImpl struct {
labelRepo LabelSQLRepository
}
var _ LabelUseCase = (*labelUseCaseImpl)(nil)
func (u *labelUseCaseImpl) AddLabel(ctx context.Context, issueID, label, actor string) error {
return u.add(ctx, issueID, label, actor, false)
}
func (u *labelUseCaseImpl) AddWispLabel(ctx context.Context, wispID, label, actor string) error {
return u.add(ctx, wispID, label, actor, true)
}
func (u *labelUseCaseImpl) add(ctx context.Context, id, label, actor string, useWisp bool) error {
if id == "" {
return fmt.Errorf("add label: id must not be empty")
}
if label == "" {
return fmt.Errorf("add label: label must not be empty")
}
if err := u.labelRepo.Insert(ctx, id, label, actor, LabelOpts{UseWispsTable: useWisp}); err != nil {
return fmt.Errorf("add label %s/%s: %w", id, label, err)
}
return nil
}
func (u *labelUseCaseImpl) RemoveLabel(ctx context.Context, issueID, label, actor string) error {
return u.remove(ctx, issueID, label, actor, false)
}
func (u *labelUseCaseImpl) RemoveWispLabel(ctx context.Context, wispID, label, actor string) error {
return u.remove(ctx, wispID, label, actor, true)
}
View on GitHub (pinned to 71377f2769)
Solutions
- Resolve and pass a valid issue ID (e.g. bd-123) before calling AddLabel/AddWispLabel.
- Check upstream code that produced the ID — a failed lookup or parse often yields an empty string.
- In scripts, quote/verify shell variables: ensure $ISSUE_ID is non-empty before invoking bd.
- If the record may not exist, fetch it first and skip the label operation when the ID is absent.
Example fix
// before
labelUC.AddLabel(ctx, issueID, "priority:high", actor) // issueID == ""
// after
if issueID == "" {
return fmt.Errorf("cannot add label: issue ID is empty")
}
labelUC.AddLabel(ctx, issueID, "priority:high", actor) Defensive patterns
Strategy: validation
Validate before calling
func addLabelSafe(ctx context.Context, uc LabelUseCase, id, label, actor string) error {
if strings.TrimSpace(id) == "" {
return errors.New("add label: issue ID is required")
}
return uc.AddLabel(ctx, id, label, actor)
} Type guard
func hasIssueID(id string) bool { return strings.TrimSpace(id) != "" } Try / catch
if err := uc.AddLabel(ctx, id, label, actor); err != nil {
if strings.Contains(err.Error(), "id must not be empty") {
return fmt.Errorf("caller bug: unresolved issue ID")
}
return err
} Prevention
- Always resolve an issue via a lookup before labeling; propagate lookup errors
- Validate IDs at CLI/tool entry points, not deep in the call stack
- In shell scripts, guard: [ -n "$ISSUE_ID" ] || exit 1
- Make unresolved-ID a typed error in your own layer so it can't silently become ""
When it happens
Trigger: Calling AddLabel(ctx, "", label, actor) or AddWispLabel(ctx, "", label, actor) — i.e. the ID argument is "", typically because an upstream lookup returned no issue or a variable was never populated.
Common situations: Scripting bd commands with variables that expand to empty (missing issue key from shell var); parsing a file where the ID column was blank; calling the Go API directly in tests/tools without resolving an ID first.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- add label: label must not be empty
- remove label: id must not be empty
- remove label: label must not be empty
- inherit labels: childID must not be empty
- inherit labels: parentID must not be empty
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/8b22f33a235b5714.
Report an issue: GitHub.