gastownhall/beads · error

add labels: %s: %w

Error message

add labels: %s: %w

What it means

Wraps an error returned by labelRepo.Insert while adding a single label via addMany (AddLabels / AddWispLabels). The message names the label that failed so callers can tell which item in the batch broke. Underlying causes come from the storage layer (record missing, constraint violation, driver error).

Source

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

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")
	}
	opts := LabelOpts{UseWispsTable: useWisp}
	for _, label := range labels {
		if label == "" {
			continue
		}
		if err := u.labelRepo.Insert(ctx, id, label, actor, opts); err != nil {
			return fmt.Errorf("add labels: %s: %w", label, err)
		}
	}
	return nil
}

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

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

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

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped error (%w) for the root storage cause and fix accordingly
  2. Confirm the issue/wisp ID exists (GetIssue/GetLabels) before adding labels
  3. Check for duplicate labels if a uniqueness constraint is reported
  4. Verify database connectivity and that the correct database/migration state is present

Example fix

// before
if err := store.AddLabels(ctx, id, labels, actor); err != nil {
	fmt.Println(err) // opaque
}
// after
if err := store.AddLabels(ctx, id, labels, actor); err != nil {
	if _, gerr := store.GetIssue(ctx, id); gerr != nil {
		return fmt.Errorf("issue %s missing: %w", id, gerr)
	}
	return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

current, err := store.GetLabels(ctx, id)
if err != nil { return err }
newLabels := slices.DeleteFunc(slices.Clone(labels), func(l string) bool {
	return l == "" || slices.Contains(current, l)
})

Try / catch

if err := store.AddLabels(ctx, id, labels, actor); err != nil {
	var label string
	if _, perr := fmt.Sscanf(err.Error(), "add labels: %s", &label); perr == nil {
		log.Printf("failed adding label %q to %s: %v", label, id, err)
	} else {
		return err
	}
}

Prevention

When it happens

Trigger: AddLabels or AddWispLabels called with a non-empty label where the labelRepo.Insert call fails: the issue/wisp ID does not exist in the table, a database constraint fires, or the storage driver errors.

Common situations: Adding labels to an issue ID that was deleted or from another database; duplicated label violating a uniqueness constraint; Dolt/driver connection problems; using a wisp ID with the non-wisp API.

Related errors


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