Skip to content

[Bug]: Failed Paykit payment request stays stuck and looks paid #1348

Closed

Description

@piotr-iohk

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

  1. Mainnet Bitkit with Paykit; add seller pubky as a contact.
  2. 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).
  3. Open the request and swipe to pay → insufficient funds.
  4. Top up the wallet so balance is clearly enough.
  5. 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):

Activity Payment Request showing -$1.04 for unpaid request

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

  1. added theissue type on Sep 28, 2026
  2. added this to the 2.7.0 milestone on Sep 28, 2026
  3. piotr-iohk commented on Sep 28, 2026

    @piotr-iohk
    CollaboratorAuthor

    Follow-up (same session, second Shop order)

    After the insufficient-funds failure on order 974b3884, a new Shop Bitcoin checkout (63869d7c, same seller ADJN…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 adjnbqbam6b6nkcjp8iarxorjmqycxo6cwfzxspeyxaqjxmnjdcy

    • Logs (UTC): continuous on-chain fee calc to bc1qw44hxxcsh67t29gm9cdmy5tvl990lan80casr9 from the earlier stuck send; repeated RecoveryRequired / resolution_failed for pubkyad…xmnjdcy; presentation stopped after 15 retries; after process restart still no Decoded incoming Paykit payment request for 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.

  4. ovitrif commented on Sep 28, 2026

    @ovitrif
    Collaborator

    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.

  5. piotr-iohk commented on Sep 28, 2026

    @piotr-iohk
    CollaboratorAuthor

    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 sendOnChain the 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.

    Build 2.5.0 (190), master bde47ec07, mainnet
    Order 131a7457 (marketplace #54)
    Amount 1303 sats (+141 fee); list 1000 + Paykit payment code
    Txid b8ebceb6694ed6d0af09e36479e721b7d887762c8ed24ff3b9e59dac661917fc
    Broadcast 10:56:20 UTC

    So 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):

    10:47–10:48  Timed out inspecting payment request support for seller
    10:49:03     Decoded incoming request
    10:55:19     Swipe confirmed
    10:56:20     Broadcast (~53s after confirm)
    

    Worth tracking as UX friction even when the happy path works; not blocking the Shop canary once on-chain confirm lands.

    Bitkit confirming

    Activity

    Payment Requests

    Logs:

    bitkit_logs_2026-09-28_11-52-33.zip

  6. modified the milestones: 2.7.0, 2.6.0 on Sep 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions