{"record":{"id":"188d46cda7824bcb","repo":"gastownhall/beads","slug":"failed-to-acquire-slot-w","errorCode":null,"errorMessage":"failed to acquire slot: %w","messagePattern":"failed to acquire slot: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/merge_slot.go","lineNumber":139,"sourceCode":"\t\t\t\t\t\treturn fmt.Errorf(\"failed to add to waiters: %w\", err)\n\t\t\t\t\t}\n\t\t\t\t\tresult.Waiting = true\n\t\t\t\t\tresult.Position = len(meta.Waiters)\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\t// Slot is available — acquire it atomically.\n\t\t\tnewMeta := slotMeta{Holder: holder, Waiters: meta.Waiters}\n\t\t\tmetaStr, err := encodeSlotMeta(newMeta)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to encode slot metadata: %w\", err)\n\t\t\t}\n\t\t\tif err := tx.UpdateIssue(ctx, slot.ID, map[string]interface{}{\n\t\t\t\t\"status\":   types.StatusInProgress,\n\t\t\t\t\"metadata\": metaStr,\n\t\t\t}, actor); err != nil {\n\t\t\t\treturn fmt.Errorf(\"failed to acquire slot: %w\", err)\n\t\t\t}\n\t\t\tresult.Acquired = true\n\t\t\tresult.Holder = holder\n\t\t\treturn nil\n\t\t},\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &result, nil\n}\n\n// MergeSlotReleaseImpl is the shared implementation of Storage.MergeSlotRelease.\nfunc MergeSlotReleaseImpl(ctx context.Context, s Storage, holder, actor string) error {\n\tslotID := MergeSlotID(ctx, s)\n\n\treturn s.RunInTransaction(ctx,\n\t\tfmt.Sprintf(\"bd: release merge slot %s\", slotID),","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/merge_slot.go#L121-L157","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry MergeSlotAcquire — the transaction guarantees atomicity so retrying is safe and race-free","Check the wrapped error for the underlying UpdateIssue cause (lock timeout vs connection vs not-found)","Recreate the slot if it was deleted: 'bd merge-slot create'","Reduce contention or increase DB lock/transaction timeouts"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if _, err := store.GetIssue(ctx, MergeSlotID(ctx, store)); err != nil { return fmt.Errorf(\"slot missing: %w\", err) }","typeGuard":null,"tryCatchPattern":"res, err := store.MergeSlotAcquire(ctx, holder, actor, false)\nif err != nil && strings.Contains(err.Error(), \"failed to acquire slot\") {\n    // Safe to retry: the transaction rolled back, slot remains free.\n    return retryWithBackoff(func() error { _, err = store.MergeSlotAcquire(ctx, holder, actor, false); return err })\n}","preventionTips":["Retry — transactional semantics make acquire idempotent and race-free","Monitor DB lock timeouts if many agents contend for the slot","Never delete the merge-slot bead while a merge queue is active","Increase transaction/lock timeouts on slow remote Dolt deployments"],"tags":["go","merge-slot","transaction","concurrency","storage"],"backgroundTag":"slot-update-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}