From 296a67770ef51bfbdf45de6ba2e478ea3e969caa Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Sun, 5 Jul 2026 11:48:04 +0100 Subject: [PATCH] fix: resolve RLock deadlock in Square mock client Move m.mu.RUnlock to defer in GetCheckout and remove duplicate RLock/RUnlock around m.completed lookup. This prevents a deadlock when CheckoutPending error is returned but the RLock was already released. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- backend/internal/square/square_dev.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/backend/internal/square/square_dev.go b/backend/internal/square/square_dev.go index 33013ff..a2979df 100644 --- a/backend/internal/square/square_dev.go +++ b/backend/internal/square/square_dev.go @@ -161,9 +161,9 @@ func (m *MockClient) GetCheckout(ctx context.Context, checkoutID string) (*Payme log.Printf("[SQUARE-MOCK] GetCheckout: id=%s", checkoutID) m.mu.RLock() - checkout, ok := m.checkouts[checkoutID] - m.mu.RUnlock() + defer m.mu.RUnlock() + checkout, ok := m.checkouts[checkoutID] if !ok { return nil, fmt.Errorf("checkout not found: %s", checkoutID) } @@ -172,10 +172,7 @@ func (m *MockClient) GetCheckout(ctx context.Context, checkoutID string) (*Payme return nil, fmt.Errorf("checkout pending") } - m.mu.RLock() result, ok := m.completed[checkoutID] - m.mu.RUnlock() - if !ok { return nil, fmt.Errorf("checkout result not found: %s", checkoutID) }