feat: retry failed quote loads and surface quote errors in TransactionPayController - #9837
Open
dan437 wants to merge 10 commits into
Open
feat: retry failed quote loads and surface quote errors in TransactionPayController#9837dan437 wants to merge 10 commits into
dan437 wants to merge 10 commits into
Conversation
A single failed quote fetch permanently stranded a transaction without quotes: errors were swallowed silently and the refresh loop skipped transactions with no quotes. Now failures are persisted to quoteError and the refresh loop retries transactions that need quotes but have none.
…retry-failed-quote-loads
dan437
marked this pull request as ready for review
August 14, 2026 09:16
matthewwalsh0
self-requested a review
August 14, 2026 10:14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Explanation
When a quote load in
TransactionPayControllerfailed unexpectedly, the error was swallowed (.catch(noop)), nothing was written to state, and the refresh loop skipped transactions with no quotes — so they were never retried. One failed fetch left the transaction permanently without quotes: clients showed no fees, and submission was blocked by the publish guard ("MetaMask Pay: Cannot submit without quote").This change makes failed quote loads recoverable:
refreshQuotesnow also retries transactions that should have quotes but have none, on the default refresh interval. One transaction's failure no longer stops the others from refreshing.QuoteRefresherkeeps the refresh loop alive while such a transaction exists.quoteError(reasonno-quotes) instead of being swallowed — but only when quotes are needed and none are usable. Existing executable quotes stay usable until a refresh replaces them, and direct routes stay silent because they need no quotes. Stale no-op quotes from a previous direct route are dropped so the retry loop picks the transaction up.quotesLastUpdated, so retries wait a full interval instead of running every tick, and late writes cannot recreate pay state that cleanup already removed.References
Checklist
Note
Medium Risk
Touches core quote fetch, refresh, and error state for pay submission; behavior is well-tested but affects when users see errors and when submit is allowed.
Overview
Fixes MetaMask Pay transactions that could stay permanently without quotes after a single failed or empty quote fetch, which blocked fees display and submit.
Quote retry and refresh loop:
refreshQuotesnow retries transactions that should have quotes but have none (failed load, empty result, fiat payment selected, etc.), respecting the normal refresh interval viaquotesLastUpdated.QuoteRefresherkeeps polling whileisQuoteRetryPendingis true, not only when executable quotes already exist. Per-transaction failures are isolated so one bad transaction does not stop others from refreshing.Failure persistence: Unexpected quote pipeline errors call
persistQuoteLoadFailure, which stampsquotesLastUpdated, setsquoteError(no-quotes) only when quotes are needed and none are usable, drops stale no-op quotes so retries can run, and skips writes if pay state was removed. Refresh paths that skip or throw still stamp attempt time so retries do not hammer every tick.Controller:
updateQuotesrejections are logged instead of swallowed withnoop, without changing the fire-and-forget call pattern.Reviewed by Cursor Bugbot for commit b94dcdd. Bugbot is set up for automated code reviews on this repo. Configure here.