Skip to content

fix(cash-link): show "Already collected" when a claim loses the race at submit - #1675

Merged
bmc08gt merged 1 commit into
code/cashfrom
fix/gift-card-claim-race
Oct 5, 2026
Merged

bmc08gt merged 1 commit into
code/cashfrom
fix/gift-card-claim-race

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator

Bugsnag 6ab9844f396a2e95206cba57: SubmitIntentError$StaleState: gift card balance has already been claimed, 108 events from 12 users, mostly on 2026.9.4.

When several people claim the same cash link, the losers can get past the pre-claim checks and are rejected at submit. In one event, GetTokenAccountInfos returned CLAIM_STATE_NOT_CLAIMED with the balance still on the card at 12:23:40.953, and the submit at 40.970 was rejected as already claimed. The client had nothing newer to check against.

ReceiveGiftCardTransactor passed that StaleState straight through. CashLinkDelegate only matches ReceiveGiftTransactorError subtypes, so these users saw "Failed to collect" instead of "Already collected".

  • ReceiveGiftCardTransactor: map the "already claimed" and "expired" StaleState reasons to AlreadyClaimed and Expired, the errors the pre-claim checks already return. Other StaleState reasons still go through logAndFail.
  • Tests: the transactor test that pinned the pass-through now expects AlreadyClaimed, plus cases for Expired and for other reasons passing through. CashLinkDelegateTest checks that AlreadyClaimed shows the "Already collected" alert.

The StaleState is still reported to Bugsnag at info level by InternalTransactionRepository, so the race stays countable.

…at submit

When several people claim the same cash link, the account query can still
return CLAIM_STATE_NOT_CLAIMED after another claim has been accepted, so the
pre-claim checks pass and SubmitIntent rejects with STALE_STATE. One Bugsnag
event (6ab9844f) shows the query returning NOT_CLAIMED 17 ms before the
rejection. ReceiveGiftCardTransactor passed that StaleState through, and
CashLinkDelegate only matches ReceiveGiftTransactorError, so the user saw
"Failed to collect".

Map the "already claimed" and "expired" StaleState reasons to AlreadyClaimed
and Expired, the errors the pre-claim checks already return. Other StaleState
reasons still go through logAndFail.
@bmc08gt bmc08gt self-assigned this Oct 5, 2026
@github-actions github-actions Bot added area: network gRPC, connectivity, API, exchange rates area: session type: fix Bug fix labels Oct 5, 2026
@bmc08gt
bmc08gt merged commit 459cfed into code/cash Oct 5, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: network gRPC, connectivity, API, exchange rates area: session type: fix Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant