gastownhall/beads · error

failed to add to waiters: %w

Error message

failed to add to waiters: %w

What it means

This error wraps a failed tx.UpdateIssue call that persists the updated waiters list to the merge slot bead's metadata while waiting for the slot. The waiter was computed but could not be written inside the acquire transaction, so the whole transaction rolls back and the caller is not registered as waiting.

Source

Thrown at internal/storage/merge_slot.go:121

			if slot.Status != types.StatusOpen {
				// Slot is held.
				if wait {
					alreadyWaiting := false
					for _, w := range meta.Waiters {
						if w == holder {
							alreadyWaiting = true
							break
						}
					}
					if !alreadyWaiting {
						meta.Waiters = append(meta.Waiters, holder)
					}
					metaStr, err := encodeSlotMeta(meta)
					if err != nil {
						return fmt.Errorf("failed to encode slot metadata: %w", err)
					}
					if err := tx.UpdateIssue(ctx, slot.ID, map[string]interface{}{"metadata": metaStr}, actor); err != nil {
						return fmt.Errorf("failed to add to waiters: %w", err)
					}
					result.Waiting = true
					result.Position = len(meta.Waiters)
				}
				return nil
			}

			// Slot is available — acquire it atomically.
			newMeta := slotMeta{Holder: holder, Waiters: meta.Waiters}
			metaStr, err := encodeSlotMeta(newMeta)
			if err != nil {
				return fmt.Errorf("failed to encode slot metadata: %w", err)
			}
			if err := tx.UpdateIssue(ctx, slot.ID, map[string]interface{}{
				"status":   types.StatusInProgress,
				"metadata": metaStr,
			}, actor); err != nil {
				return fmt.Errorf("failed to acquire slot: %w", err)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry MergeSlotAcquire — the transaction is atomic, so retry is safe
  2. Verify the slot exists with 'bd merge-slot create' / bd show of the slot ID
  3. Check database connectivity and lock contention (other long-running transactions)
  4. Inspect the wrapped error (%w) for the root cause from UpdateIssue
Defensive patterns

Strategy: retry

Validate before calling

if _, err := store.GetIssue(ctx, MergeSlotID(ctx, store)); err != nil || err == nil && slotNil { /* recreate slot */ }

Try / catch

res, err := store.MergeSlotAcquire(ctx, holder, actor, true)
if err != nil && strings.Contains(err.Error(), "failed to add to waiters") {
    return retryWithBackoff(func() error { _, err = store.MergeSlotAcquire(ctx, holder, actor, true); return err })
}

Prevention

When it happens

Trigger: MergeSlotAcquire with wait=true while the slot is held, and tx.UpdateIssue on the slot ID fails — e.g. database lock timeout, connection loss mid-transaction, the slot issue was deleted concurrently, or a storage-layer validation rejected the metadata string.

Common situations: Two agents contending for the merge slot on a slow or remote Dolt database; slot bead deleted or renamed by manual cleanup; transient DB outage during high-contention merges.

Related errors


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