gastownhall/beads · error
merge slot not found: %s
Error message
merge slot not found: %s
What it means
MergeSlotReleaseImpl could not fetch the merge slot bead (GetIssue returned an error or nil) while releasing it. The slot ID is derived from the issue_prefix config (e.g. gt-merge-slot), so this usually means the slot bead does not exist under the expected ID.
Source
Thrown at internal/storage/merge_slot.go:161
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),
func(tx Transaction) error {
slot, err := tx.GetIssue(ctx, slotID)
if err != nil || slot == nil {
return fmt.Errorf("merge slot not found: %s", slotID)
}
meta := parseSlotMeta(slot)
if holder != "" && meta.Holder != holder {
return fmt.Errorf("slot held by %s, not %s", meta.Holder, holder)
}
if slot.Status == types.StatusOpen {
// Already released; idempotent.
return nil
}
newMeta := slotMeta{Waiters: meta.Waiters}
metaStr, err := encodeSlotMeta(newMeta)
if err != nil {
return fmt.Errorf("failed to encode slot metadata: %w", err)
}View on GitHub (pinned to 71377f2769)
Solutions
- Run 'bd merge-slot create' to create the slot bead, then retry the release
- Verify the slot exists under the expected ID (prefix + '-merge-slot') with bd show
- Check the issue_prefix config has not changed since the slot was created
- If the slot is gone but work completed, the release can often be skipped — the slot is free by definition
Example fix
// before
err := store.MergeSlotRelease(ctx, holder, actor) // fails: slot missing
// after
if _, err := store.MergeSlotCreate(ctx, actor); err != nil { return err } // idempotent
return store.MergeSlotRelease(ctx, holder, actor) Defensive patterns
Strategy: validation
Validate before calling
slotID := MergeSlotID(ctx, store)
if slot, err := store.GetIssue(ctx, slotID); err != nil || slot == nil {
if _, err := store.MergeSlotCreate(ctx, actor); err != nil { return err }
} Type guard
func slotExists(ctx context.Context, s Storage) bool {
slot, err := s.GetIssue(ctx, MergeSlotID(ctx, s))
return err == nil && slot != nil
} Try / catch
if err := store.MergeSlotRelease(ctx, holder, actor); err != nil {
var nf *NotFoundError
if errors.As(err, &nf) || strings.Contains(err.Error(), "merge slot not found") {
// Slot gone = lock already free; recreate for future use and continue.
_, cerr := store.MergeSlotCreate(ctx, actor)
return cerr
}
return err
} Prevention
- Run 'bd merge-slot create' once before using the merge queue (it is idempotent)
- Keep the issue_prefix config stable; changing it changes the slot ID
- Exclude internal gt:slot-labeled beads from cleanup/prune scripts
- Check slot existence with MergeSlotCheck before release if unsure
When it happens
Trigger: Calling MergeSlotRelease (bd merge-slot release) when the slot bead was never created, was deleted manually, or the issue_prefix config changed so a different slot ID is computed than the one that exists.
Common situations: Fresh database where 'bd merge-slot create' was never run; someone deleted the internal merge-slot issue; config prefix changed between create and release (e.g. migrating from bd- to gt- prefix).
Related errors
- no store is open for this workspace
- %w: issue %s
- wisp %s not found
- failed to get issue for update: %w
- failed to encode slot metadata: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/87f94cb11e1dc0ba.
Report an issue: GitHub.