gastownhall/beads · error

failed to acquire slot: %w

Error message

failed to acquire slot: %w

What it means

This error wraps a failed tx.UpdateIssue that would have flipped the slot to StatusInProgress and written the new holder's metadata. The atomic check-and-set succeeded (slot was open) but the write failed, so the transaction rolls back and the slot remains free.

Source

Thrown at internal/storage/merge_slot.go:139

						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)
			}
			result.Acquired = true
			result.Holder = holder
			return nil
		},
	)
	if err != nil {
		return nil, err
	}
	return &result, nil
}

// MergeSlotReleaseImpl is the shared implementation of Storage.MergeSlotRelease.
func MergeSlotReleaseImpl(ctx context.Context, s Storage, holder, actor string) error {
	slotID := MergeSlotID(ctx, s)

	return s.RunInTransaction(ctx,
		fmt.Sprintf("bd: release merge slot %s", slotID),

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry MergeSlotAcquire — the transaction guarantees atomicity so retrying is safe and race-free
  2. Check the wrapped error for the underlying UpdateIssue cause (lock timeout vs connection vs not-found)
  3. Recreate the slot if it was deleted: 'bd merge-slot create'
  4. Reduce contention or increase DB lock/transaction timeouts
Defensive patterns

Strategy: retry

Validate before calling

if _, err := store.GetIssue(ctx, MergeSlotID(ctx, store)); err != nil { return fmt.Errorf("slot missing: %w", err) }

Try / catch

res, err := store.MergeSlotAcquire(ctx, holder, actor, false)
if err != nil && strings.Contains(err.Error(), "failed to acquire slot") {
    // Safe to retry: the transaction rolled back, slot remains free.
    return retryWithBackoff(func() error { _, err = store.MergeSlotAcquire(ctx, holder, actor, false); return err })
}

Prevention

When it happens

Trigger: MergeSlotAcquire on an open slot where tx.UpdateIssue on the slot ID fails: DB connection loss, lock timeout under contention (two acquirers racing, loser hits a write conflict), the slot bead was deleted between GetIssue and UpdateIssue, or a storage constraint/validation rejection.

Common situations: Racing agents acquiring the merge slot simultaneously on a busy Dolt database; network blip to a remote Dolt server; manual deletion of the merge-slot bead during an active merge queue.

Related errors


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