Skip to content

system back on the recovery pin screen blocks retry original payment until restart #1548

Open

Description

@jvsena42

Observed

On Payment Pending, after Retry original payment → fee → Authorize retry, pressing system Back on the payment PIN screen leaves the retry flow stuck. Every later Retry original payment never reaches fee approval: Continue stays disabled until the app is force-stopped. Back on the fee-approval step is fine, and so is the header Back on the PIN screen.

17:38:59.138 VERBOSE [LightningRepo.kt:259] Operation called: 'retryOriginalOnchainSend'
17:38:59.588 INFO  [ldk_node::wallet:1962] Created new transaction 70bc54b2…d154 sending 2000sats …   (PIN screen, then system Back)
17:46:27.251 VERBOSE [LightningRepo.kt:259] Operation called: 'retryOriginalOnchainSend'   (no transaction follows)
17:49:43.257 VERBOSE [LightningRepo.kt:259] Operation called: 'retryOriginalOnchainSend'   (no transaction follows; button disabled 2+ min)

Reproduced twice, on master + ldk-node rc.76 (#1532 head 5a8e435) on the emulator.

Expected

System Back on the PIN screen cancels the retry the same way the header Back does. The original payment stays pending, and Retry original payment works again without restarting the app.

Steps to reproduce

  1. Turn on PIN with "Require PIN for payments".
  2. Make an on-chain send whose broadcast times out, so Payment Pending shows "Retry original payment". For example, block Electrum traffic during the broadcast.
  3. Tap Retry original payment, enter a fee rate, Continue, then Authorize retry. The PIN screen opens.
  4. Press system Back.
  5. Tap Retry original payment again and continue. It never reaches fee approval.

Root cause

SendSheet.kt:559 sets RECOVERY_PIN_CHECK_RESULT_KEY = false only in the PIN screen's header onBack, and :564 sets true on success. SendPinCheckScreen has no BackHandler, so system Back pops the route without an answer. The CompletableDeferred in SendPendingViewModel never completes. OnchainSendCoordinator.retryOriginal stays suspended inside mutex.withLock, where approvePrepared / authorizeOriginal run, so every later retry waits on that lock.

Suggested fix

Treat route pop without a result as a cancel: add a BackHandler on RecoveryPinCheck that sets the key to false, or complete the deferred with false when the destination leaves the back stack. Also avoid holding the coordinator mutex across user-interaction awaits, so an abandoned approval cannot block later retries.

Journey: journeys/send/onchain-original-payment-retry.xml action 8 covers system Back on the PIN screen. Add a check that a later retry still reaches fee approval.

Came in with #1384, so it ships in 3.0.0.

Activity

  1. added this to the 3.0.5 milestone on Oct 16, 2026
  2. self-assigned this
    on Oct 19, 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

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions