Repository navigation
[Bug]: Failed Paykit payment request stays stuck and looks paid #1348
Description
Twin: synonymdev/bitkit-ios#776
What happened?
Incoming Paykit payment request from a Pubky Shop seller (ADJN…JDCY / contact “pav C tester”) arrived and opened the send flow. Swipe to pay failed with insufficient funds (wallet had 2000 sats; need ≥2255 for 1255 + fee).
After topping up to 7000 sats, pay and dismiss both failed with toast “Payment request operation is already in progress”. Later toast “The payment request is no longer available.” The request disappeared from the actionable list, then reappeared in Activity looking like a completed outflow (-$1.04 / ₿1255) even though no transaction was broadcast. Further resolution attempts log RecoveryRequired / resolution_failed and never reopen a payable sheet.
Expected behavior
A send that fails before broadcast should leave the payment request payable (or cleanly dismissible/rejectable). Activity should not show an unpaid request as a completed negative amount. After funding, the user should be able to pay or dismiss without “already in progress” / “no longer available”.
Steps to Reproduce
- Mainnet Bitkit with Paykit; add seller pubky as a contact.
- Receive an incoming on-chain Paykit payment request for more than current spendable balance (here: 1255 sats request, 2000 sats on-chain, fees push need to ≥2255).
- Open the request and swipe to pay → insufficient funds.
- Top up the wallet so balance is clearly enough.
- Try to pay again or dismiss the request → “already in progress”, then “no longer available”; Activity may still show the request looking paid.
Logs / Screenshots / Recordings
Insufficient-funds pay attempt:
2026-09-28-paykit-failed-send-stuck-retry-insufficient-funds.mp4
Retry / dismiss after top-up (“already in progress”):
2026-09-28-paykit-failed-send-stuck-retry-already-in-progress.mp4
Ghost Activity detail (looks paid, was not):
Logs (parts covering decode → fail → RecoveryRequired loop + filtered excerpt):
2026-09-28-paykit-failed-send-stuck-retry-logs.zip
Key log lines (UTC):
08:30:25 Decoded incoming Paykit payment request target
08:30:25 Selected UTXOs have insufficient value. Have: 2000sats, Need at least: 2255sats
08:34:59 sendOnChain: sats=1255, … satsPerVByte=2
08:35:04 Error executing 'sendOnChain' [… insufficient …]
08:35:13 Rejected incoming Paykit payment request presentation: … reason='resolution_failed'
08:37:45+ Failed to resolve … errorType='RecoveryRequired' (repeats)
08:39:04 Balances … totalOnchainSats:7000 (still stuck)
Bitkit Version
2.5.0 (190), mainnet debug (to.bitkit), master at 4b5e73f00 (chore: restore the payment request changelog entry)
Device / OS
Samsung Galaxy S22 (SM-S901B), Android 16 (API 36)
Reproducibility
Often (>50%) — reproduced once end-to-end on mainnet Shop canary; matches the iOS “failed send before broadcast” class (#776)
Additional context
- Triggered during Pubky Shop Bitcoin canary (pubky-marketplace#54), order
974b3884. Shop delivery worked after the seller was added as a contact; failure is on the Bitkit pay/retry path. - Listing priced 1000 sats; Bitkit showed 1255 sats for the request.
- Same class as iOS #776 (consume private payment list / accept before successful broadcast). Related closed Android HW case: #1227.
- No on-chain payment was broadcast; funds remain in the wallet.

Activity
piotr-iohk commentedon Sep 28, 2026
Follow-up (same session, second Shop order)
After the insufficient-funds failure on order
974b3884, a new Shop Bitcoin checkout (63869d7c, same sellerADJN…JDCY/ contact “pav C tester”) still could not be paid.Observed
Shop: “Delivered to your wallet. Open Bitkit to pay.”
Bitkit: request shows under Payment Requests (bell), no auto swipe sheet.
Tap Pay: nothing / then toast “Payment request operation is already in progress.”
Force-stop Bitkit → open Payment Requests → Dismiss shows error toast:
code=recovery_required, context=Encrypted Link Handshake is still in progress for counterparty adjnbqbam6b6nkcjp8iarxorjmqycxo6cwfzxspeyxaqjxmnjdcyLogs (UTC): continuous on-chain fee calc to
bc1qw44hxxcsh67t29gm9cdmy5tvl990lan80casr9from the earlier stuck send; repeatedRecoveryRequired/resolution_failedforpubkyad…xmnjdcy; presentation stopped after 15 retries; after process restart still noDecoded incoming Paykit payment requestfor the new order.Balance was sufficient (~7000 sats) on the second attempt — not an underfund issue.
Takeaway
Failed pay before broadcast leaves the private Paykit link to that counterparty in
recovery_required/ handshake-in-progress. Later requests from the same seller contact stay undismissable/unpayable. Matches the stuck-after-failed-send class (see also iOS #776).Next for the Shop canary
Abandoning this wallet/profile for further retries against this seller. Will continue the marketplace canary on a fresh Bitkit profile + new wallet (seller re-added as contact only after clean state), and treat further unblock work for this identity as in-scope for this bug.
ovitrif commentedon Sep 28, 2026
IIRC my agent during demo recording also flagged this. Might have to fix it in
2.6.0, I will update the milestone if so.piotr-iohk commentedon Sep 28, 2026
Fresh wallet canary: pay succeeded (workaround)
John’s note on marketplace #54 matches what we saw: Shop did not void/replace the old requests; after failed
sendOnChainthe wallet stayed on “already in progress” /recovery_required(Encrypted Link Handshake in progress for the seller). Expired requests correctly became “no longer available.”Workaround that worked: new Bitkit profile + new wallet, seller added as contact first, then Shop checkout.
masterbde47ec07, mainnet131a7457(marketplace #54)b8ebceb6694ed6d0af09e36479e721b7d887762c8ed24ff3b9e59dac661917fcSo this issue is about recovery after a failed private Paykit pay, not about Shop delivery or the random payment-code sats.
Latency on the successful path (same session, UTC):
Worth tracking as UX friction even when the happy path works; not blocking the Shop canary once on-chain confirm lands.
Logs:
bitkit_logs_2026-09-28_11-52-33.zip