gastownhall/beads · error

remove label: label must not be empty

Error message

remove label: label must not be empty

What it means

A guard error from label remove(): it rejects an empty label string. RemoveLabel/RemoveWispLabel validate arguments before calling labelRepo.Delete, so an empty label never reaches storage.

Source

Thrown at internal/storage/domain/label.go:85

		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)
}

func (u *labelUseCaseImpl) remove(ctx context.Context, id, label, actor string, useWisp bool) error {
	if id == "" {
		return fmt.Errorf("remove label: id must not be empty")
	}
	if label == "" {
		return fmt.Errorf("remove label: label must not be empty")
	}
	if err := u.labelRepo.Delete(ctx, id, label, actor, LabelOpts{UseWispsTable: useWisp}); err != nil {
		return fmt.Errorf("remove label %s/%s: %w", id, label, err)
	}
	return nil
}

func (u *labelUseCaseImpl) AddLabels(ctx context.Context, issueID string, labels []string, actor string) error {
	return u.addMany(ctx, issueID, labels, actor, false)
}

func (u *labelUseCaseImpl) AddWispLabels(ctx context.Context, wispID string, labels []string, actor string) error {
	return u.addMany(ctx, wispID, labels, actor, true)
}

func (u *labelUseCaseImpl) addMany(ctx context.Context, id string, labels []string, actor string, useWisp bool) error {
	if id == "" {
		return fmt.Errorf("add labels: id must not be empty")

View on GitHub (pinned to 71377f2769)

Solutions

  1. Pass a non-empty label string to RemoveLabel/RemoveWispLabel.
  2. Filter empty strings out of label lists before removal, or use RemoveLabels which handles lists.
  3. Trim and validate user-provided label input at the entry point.
  4. If the label is optional in your flow, skip the remove call when it's blank.

Example fix

// before
labelUC.RemoveLabel(ctx, id, cfg.Label, actor) // cfg.Label may be ""

// after
if cfg.Label != "" {
    labelUC.RemoveLabel(ctx, id, cfg.Label, actor)
}
Defensive patterns

Strategy: validation

Validate before calling

func removeLabelSafe(ctx context.Context, uc LabelUseCase, id, label, actor string) error {
    if strings.TrimSpace(label) == "" {
        return nil // nothing to remove; treat as no-op
    }
    return uc.RemoveLabel(ctx, id, label, actor)
}

Type guard

func hasLabel(label string) bool { return strings.TrimSpace(label) != "" }

Try / catch

if err := uc.RemoveLabel(ctx, id, label, actor); err != nil {
    if strings.Contains(err.Error(), "label must not be empty") {
        return nil // treat blank label as a no-op
    }
    return err
}

Prevention

When it happens

Trigger: Calling RemoveLabel(ctx, id, "", actor) or RemoveWispLabel(ctx, id, "", actor) — an empty label literal or a blank token produced by splitting/parsing label input.

Common situations: Comma-separated label lists with empty entries ("p1,,p2"); shell variables expanding to nothing; UI/tool code passing an unselected (empty) label value.

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/3533c78b711386df. Report an issue: GitHub.