gastownhall/beads · error

set labels: list current: %w

Error message

set labels: list current: %w

What it means

Wraps a failure from labelRepo.List inside setMany (SetLabels / SetWispLabels). SetLabels must read the current labels to compute the diff before mutating; if that read fails, the whole set operation is aborted with no changes made. The error preserves the underlying cause via %w.

Source

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

	return nil
}

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

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

func (u *labelUseCaseImpl) setMany(ctx context.Context, id string, labels []string, actor string, useWisp bool) error {
	if id == "" {
		return fmt.Errorf("set labels: id must not be empty")
	}
	opts := LabelOpts{UseWispsTable: useWisp}
	current, err := u.labelRepo.List(ctx, id, opts)
	if err != nil {
		return fmt.Errorf("set labels: list current: %w", err)
	}
	desired := make(map[string]bool, len(labels))
	for _, l := range labels {
		if l != "" {
			desired[l] = true
		}
	}
	existing := make(map[string]bool, len(current))
	for _, l := range current {
		existing[l] = true
		if !desired[l] {
			if err := u.labelRepo.Delete(ctx, id, l, actor, opts); err != nil {
				return fmt.Errorf("set labels: remove %s: %w", l, err)
			}
		}
	}
	for l := range desired {
		if !existing[l] {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the wrapped error for the storage root cause
  2. Verify database connectivity and that migrations have run
  3. Retry the operation — the read failed before any mutation, so it is safe to retry
  4. Confirm you are pointed at the correct database (right repo/dolt remote)

Example fix

// before
err := store.SetLabels(ctx, id, desired, actor) // opaque
// after
if err := store.SetLabels(ctx, id, desired, actor); err != nil {
	if errors.Is(err, driverConnErr) { time.Sleep(retryBackoff); err = store.SetLabels(ctx, id, desired, actor) }
	return err
}
Defensive patterns

Strategy: retry

Validate before calling

// No caller-side validation applies; ensure connectivity before the call.
if _, err := store.GetLabels(ctx, id); err != nil {
	return fmt.Errorf("storage unavailable before SetLabels: %w", err)
}

Try / catch

err := store.SetLabels(ctx, id, desired, actor)
for i := 0; err != nil && i < 3; i++ {
	time.Sleep(time.Duration(1<<i) * 100 * time.Millisecond)
	err = store.SetLabels(ctx, id, desired, actor) // safe: read failed before mutation
}

Prevention

When it happens

Trigger: SetLabels/SetWispLabels called on a valid ID but labelRepo.List fails: storage driver error, database unavailable, table missing/mis-migrated, or transaction conflict.

Common situations: Dolt/driver connectivity problems; running against a database created before labels tables existed (migration missing); transient conflicts while other agents write concurrently.

Related errors


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