Paradaux
IssuesPAR-102Done
0

Idempotent transfer retry races on the dedup check-then-insert (500 instead of replay)

Pre-existing (not introduced by the develop→main release; surfaced during the release audit of PR #11).

In TransferService.transfer, the idempotency path is check-then-act: findByDedupKey → if null, proceed to insertTxn. Two concurrent requests carrying the same Idempotency-Key (same source account) can both read null and both proceed; the second insert violates the client_dedup_key UNIQUE constraint and the request fails with a 500 instead of replaying the first transaction's response.

Not a money-safety issue — the UNIQUE constraint prevents the double-insert, so there's no double-spend; the loser just gets an error rather than the idempotent replay it asked for. Severity low (rare: requires truly simultaneous retries).

Fix options: catch the duplicate-key DataIntegrityViolationException on insert and re-run findByDedupKeyreplayIdempotent (treat the constraint violation as "someone else won the race, replay theirs"); or take a short advisory lock keyed on the dedup hash around the check-insert. The catch-and-replay approach is smaller and matches the existing replay semantics.

Out of scope for the current release PR — the F2 idempotency-scoping commit only changed what the key is derived from, not the concurrency model.

Comments

No comments yet.

Activity

  • ParadauxIO linked a commit — Commit f5c76e2 — Release treasury-rest-api 2.1.0 (PAR-39, PAR-102, PAR-116)Jun 7, 2026, 2:51 PM
  • ParadauxIO linked a commit — Commit 80275ab — Replay idempotent transfers that race on the dedup insert (PAR-102)Jun 7, 2026, 2:51 PM
  • ParadauxIO changed status to Status → DoneJun 7, 2026, 2:51 PM
  • ParadauxIO linked a commit — Commit f5c76e2 — Release treasury-rest-api 2.1.0 (PAR-39, PAR-102, PAR-116)Jun 7, 2026, 2:51 PM
  • tesks changed status to Status → Pending ReleaseJun 6, 2026, 11:40 AM
  • ParadauxIO linked a commit — Commit 80275ab — Replay idempotent transfers that race on the dedup insert (PAR-102)Jun 6, 2026, 11:40 AM
  • tesks created the issueJun 6, 2026, 11:20 AM