fix(cashu): stop transient outputs-pending (11004) from crashing swap tasks#1115
fix(cashu): stop transient outputs-pending (11004) from crashing swap tasks#1115orveth wants to merge 1 commit into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
Cross-lane review note (keeper coordination): Domain owner for cashu error-codes reviewed the classification — no conflict. The operation-level classifier is a separate future file ( On the open retry question: both the domain owner and I recommend bounded retry + log over the current silent-infinite retry, so a never-settling swap (inputs spent elsewhere / keyset-counter desync) stays observable rather than spinning quietly forever. Happy to switch it if you agree — small change. |
… tasks Rebased onto post-monorepo master; paths relocated app/ -> apps/web-wallet/app/. Original commits: - fix(cashu): stop transient outputs-pending (11004) from crashing swap tasks
28c3524 to
88c6239
Compare
Problem
Sentry 7512228812 —
MintOperationError: outputs are pending(cashu error code 11004OUTPUTS_ARE_PENDING), recurring in production. It crashes the task-processing lead client to the root error boundary ("Oops, something went wrong / Reload Page").Chain: the background
TaskProcessor(rendered only on the lead client) runs the cashu send-swap task →swapProofs(cashu-send-swap-service.ts). Its catch recovers onlyOUTPUT_ALREADY_SIGNED(11003) andTOKEN_ALREADY_SPENT(11001) viawallet.restore(); 11004 is not in the allowlist, so it re-throws. The mutation runsretry: 3+throwOnError: true, so once retries exhaust the error is thrown during render → root boundary +Sentry.captureException. (These send/receive flows have no explicit capture, so the Sentry Issue is the boundary firing.)Fix
OUTPUTS_ARE_PENDING(11004) andPROOFS_ARE_PENDING(11002) are transient — the mint is still processing the outputs/inputs in a parallel operation and resolves them on its own. They need retry-until-resolved, notwallet.restore()(the outputs aren't signed yet — distinct from the 11003 path).Two layers, both leaning on the existing
ConcurrencyError("always retry") convention — not a new operation-level classifier (that stays out of scope):isTransientCashuSwapErrorpredicate (app/lib/cashu/error-codes.ts). Both swap services'swapProofscatch now map it →throw new ConcurrencyError(error.message), after (and distinct from) the existing 11003/11001wallet.restore()recovery.swapForProofsToSendand receivecompleteSwaptask mutations go fromretry: 3/throwOnError: trueto a type-awareretry(ConcurrencyError→ retry, mirroringuseCreateCashuSendSwapin the same file) plusthrowOnError: (e) => !(e instanceof ConcurrencyError). Transient errors retry until the mint settles and never reach the boundary; the swap row staysDRAFTand self-heals on the next trigger cycle. Unexpected errors keep their existing loud-fail behavior.Reviewer notes
cashu-receive-swap-servicehas the identical 11003/11001-only allowlist and itscompleteSwaphook the identicalretry: 3/throwOnError: true→ the same latent 11004 crash. Both are fixed for consistency.ConcurrencyErrorindefinitely (matchinguseCreateCashuSendSwap) means a persistently-stuck pending state retries silently — the mutation never settles, soonErrornever fires and nothing escalates, leaving no alert (the very signal that surfaced this bug). If preferred, a follow-up can bound the retry and log on give-up. Flagging for a decision.error-codes.test.tslocks the classification (11004/11002 transient; 11003/11001/others not). A full service/hook render test isn't feasible here: importingCashuSendSwapServiceunderbun testthrowswindow is not defined(the Supabase client + realtime manager touchwindowat module top-level), which is why every existing repo test exercises pure modules only. The throw-conversion and retry config are covered bytsc+ the conventions they mirror.Verification
bun run fix:all— cleanbun run typecheck— cleanbun test— 139 pass / 0 fail (incl. the new 6-case predicate test)Draft for review (gudnuf approved a draft fix).
🤖 Generated with Claude Code