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

  1. Resolve and pass a valid issue ID (e.g. bd-123) before calling AddLabel/AddWispLabel.
  2. Check upstream code that produced the ID — a failed lookup or parse often yields an empty string.
  3. In scripts, quote/verify shell variables: ensure $ISSUE_ID is non-empty before invoking bd.
  4. 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

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


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