Skip to content

fix(ramp): localize circuit breaker fallback errors#29507

Open
saustrie-consensys wants to merge 27 commits into
mainfrom
saustrie-consensys/TRAM-3475-circuit-breaker-open-error
Open

fix(ramp): localize circuit breaker fallback errors#29507
saustrie-consensys wants to merge 27 commits into
mainfrom
saustrie-consensys/TRAM-3475-circuit-breaker-open-error

Conversation

@saustrie-consensys
Copy link
Copy Markdown
Contributor

@saustrie-consensys saustrie-consensys commented Apr 29, 2026

Description

This PR is the mobile companion to MetaMask/core#8596.

When the ramps controller classifies a temporary provider/compliance failure as CIRCUIT_BREAKER_OPEN, mobile still had one important leak in Unified Buy V2: the quote path could collapse the enriched controller/query error back down to a raw string, which meant the Buy amount screen could still show Execution prevented because the circuit breaker is open.

  1. What is the reason for the change?
    Mobile was already translating keyed ramp resource errors in several places, but the V2 quote flow was still dropping errorKey metadata and treating the resulting message as user-facing copy.
  2. What is the improvement/solution?
    Preserve the original quote error object in useRampsQuotes, route quote-driven UI states back through parseUserFacingError, and map CIRCUIT_BREAKER_OPEN to a dedicated high-level fallback: This service is temporarily unavailable. Please try again in about 30 minutes.

That wording is intentional. The core service-policy cooldown defaults to 30 minutes, but the current ramps error contract does not expose a live remaining-duration value, so mobile should avoid promising an exact countdown once the breaker is already partway through its cooldown.

This stays a draft because it depends on the companion core change from MetaMask/core#8596 being available in the mobile-consumed @metamask/ramps-controller build.

Changelog

CHANGELOG entry: Fixed a bug where Unified Buy could show an internal circuit breaker error instead of localized retry copy.

Related issues

Fixes: https://consensyssoftware.atlassian.net/browse/TRAM-3475

Companion core change: MetaMask/core#8596

Manual testing steps

Feature: Unified Buy circuit breaker fallback uses localized copy

  Scenario: Quote fetch hits the ramps circuit breaker
    Given the user is in Unified Buy V2
    And the ramps controller returns a quote failure tagged with CIRCUIT_BREAKER_OPEN
    When the Buy amount screen renders the quote error banner
    Then the user should see "This service is temporarily unavailable. Please try again in about 30 minutes."
    And the raw text "Execution prevented because the circuit breaker is open" should not be shown

  Scenario: Other ramp catalog resources hit the same circuit breaker classification
    Given the ramps controller returns providers, tokens, countries, or payment methods errors tagged with CIRCUIT_BREAKER_OPEN
    When the corresponding mobile ramp hook exposes the error state
    Then the UI should surface the dedicated circuit-breaker fallback copy
    And non-circuit-breaker errors should continue to surface their existing messages

Screenshots/Recordings

Before (main)

before-buy-broken-circuit-main.mp4

After (this PR + core PR branch)

after-buy-broken-circuit-pr-branches-rerecord.mp4

Validation

  • ./node_modules/.bin/jest --runTestsByPath app/components/UI/Ramp/hooks/useRampsQuotes.test.ts app/components/UI/Ramp/utils/parseUserFacingError.test.ts app/components/UI/Ramp/hooks/useRampsProviders.test.ts app/components/UI/Ramp/hooks/useRampsCountries.test.ts app/components/UI/Ramp/hooks/useRampsTokens.test.ts app/components/UI/Ramp/hooks/useRampsPaymentMethods.test.ts --runInBand
  • yarn eslint app/components/UI/Ramp/hooks/useRampsQuotes.ts app/components/UI/Ramp/hooks/useRampsQuotes.test.ts app/components/UI/Ramp/Views/Modals/ProviderSelectionModal/ProviderSelectionModal.tsx app/components/UI/Ramp/Views/BuildQuote/BuildQuote.tsx app/components/UI/Ramp/utils/parseUserFacingError.ts app/components/UI/Ramp/utils/parseUserFacingError.test.ts app/components/UI/Ramp/hooks/useRampsProviders.test.ts app/components/UI/Ramp/hooks/useRampsCountries.test.ts app/components/UI/Ramp/hooks/useRampsTokens.test.ts app/components/UI/Ramp/hooks/useRampsPaymentMethods.test.ts
  • yarn lint:tsc

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
  • I've tested with a power user scenario
  • I've instrumented key operations with Sentry traces for production performance metrics

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Low Risk
Low risk: changes are limited to error-message parsing/localization and test infrastructure, with minimal impact on core ramp flows beyond how errors are displayed and tracked.

Overview
Unified Buy V2 now preserves quote-fetch error objects (instead of collapsing to strings) so errorKey metadata survives through useRampsQuotes into BuildQuote, enabling circuit-breaker errors to display a localized fallback message and be tracked consistently.

parseUserFacingError is extended to detect CIRCUIT_BREAKER_OPEN and return a new localized string (fiat_on_ramp.circuit_breaker_open), and ramp hooks/screens that surface catalog/quote errors (useRampsProviders, useRampsTokens, useRampsCountries, useRampsPaymentMethods, ProviderSelectionModal) now run errors through this parser.

Adds/updates tests to cover circuit-breaker localization and banner clearing on recovery, bumps @metamask/ramps-controller/@metamask/messenger, and makes websocket server tests more reliable by using ephemeral ports and awaiting listening/error events.

Reviewed by Cursor Bugbot for commit bcfc471. Bugbot is set up for automated code reviews on this repo. Configure here.

@github-actions
Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@saustrie-consensys saustrie-consensys added team-money-movement issues related to Money Movement features team-ramps labels Apr 29, 2026
Copy link
Copy Markdown
Contributor Author

Follow-up note after tightening the companion core PR.

No additional mobile code change was needed here because the mobile layer is already using the right boundary: parseUserFacingError treats errorKey as the stable contract and does not need to know about BrokenCircuitError, Cockatiel, or @metamask/controller-utils.

That separation is intentional:

  • core classifies internal/transient infrastructure failures like the circuit breaker and attaches errorKey
  • mobile maps that key to localized fallback copy
  • raw provider/business errors can still continue through the existing parsing path when they are actually useful user-facing messages

With the latest core follow-up now normalizing CIRCUIT_BREAKER_OPEN across more Transak methods, the existing mobile catch paths and hooks in this PR benefit automatically without adding any new client-side string matching.

@saustrie-consensys saustrie-consensys self-assigned this Apr 29, 2026
@saustrie-consensys saustrie-consensys force-pushed the saustrie-consensys/TRAM-3475-circuit-breaker-open-error branch from 1eb7801 to eaf2edb Compare April 29, 2026 22:17
@saustrie-consensys saustrie-consensys marked this pull request as ready for review April 30, 2026 21:57
@saustrie-consensys saustrie-consensys requested a review from a team as a code owner April 30, 2026 21:57
@saustrie-consensys
Copy link
Copy Markdown
Contributor Author

Dependency note after checking the release path:

This PR is the correct mobile-side handling change, but it does not complete the rollout by itself because mobile still resolves @metamask/ramps-controller@13.2.0 today.

The companion core fix from MetaMask/core#8596 has now been added to the open core release PR MetaMask/core#8685 as @metamask/ramps-controller@13.3.0.

Why that matters:

  • this PR localizes CIRCUIT_BREAKER_OPEN once mobile receives it from core
  • the currently published 13.2.0 package does not emit that stable error key
  • after core#8685 merges and npm publication completes, mobile still needs a normal consumer refresh so this branch stops resolving 13.2.0 and picks up the released 13.3.0 package

Ships @metamask/ramps-controller@13.3.0 (released in MetaMask/core#8698)
so this branch can consume the stable `CIRCUIT_BREAKER_OPEN` error key
the rest of the diff localizes against.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
saustrie-consensys and others added 4 commits May 6, 2026 16:57
Pins the project's direct messenger dep (and resolution override) to
^1.2.0 so the messenger@^1.2.0 lockfile entry pulled in by
@metamask/ramps-controller@13.3.0 is rooted at the project. Without this
the previous commit's lockfile is unstable under yarn install --immutable
on CI: the messenger@^1.2.0 entry gets flagged as orphan and the install
fails with YN0028.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…AM-3475-circuit-breaker-open-error

# Conflicts:
#	yarn.lock
Collapses the duplicate `@metamask/ramps-controller` entries (13.2.0
pulled in by transaction-pay-controller@21.0.0 via ^13.2.0 + 13.3.0
from the direct dep) into a single 13.3.0 resolution, since 13.3.0
satisfies both ranges. Fixes the `Dedupe` CI check.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…AM-3475-circuit-breaker-open-error

# Conflicts:
#	yarn.lock
@saustrie-consensys saustrie-consensys requested a review from a team as a code owner May 8, 2026 09:59
@saustrie-consensys saustrie-consensys requested a review from a team as a code owner May 8, 2026 10:54
Comment thread app/components/UI/Ramp/Views/BuildQuote/BuildQuote.tsx
amitabh94
amitabh94 previously approved these changes May 11, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
amitabh94
amitabh94 previously approved these changes May 12, 2026
@amitabh94 amitabh94 removed the request for review from meltingice1337 May 12, 2026 20:59
@saustrie-consensys
Copy link
Copy Markdown
Contributor Author

@metamaskbot update-mobile-fixture

@github-actions
Copy link
Copy Markdown
Contributor

🔄 Fixture update started. Running workflow from branch saustrie-consensys/TRAM-3475-circuit-breaker-open-error. View workflow runs

@github-actions
Copy link
Copy Markdown
Contributor

E2E fixture update failed.\n\nCommon causes:\n- CI workflow is still running — wait for 'Build iOS Apps' to complete\n- CI workflow was skipped — ensure your PR has iOS-impacting changes or use skip-smart-e2e-selection label\n- iOS build failed — check the CI workflow for errors\n\nView logs and retry

@amitabh94
Copy link
Copy Markdown
Contributor

@copilot resolve conflicts

…-open-error

Co-authored-by: amitabh94 <12572750+amitabh94@users.noreply.github.com>
auto-merge was automatically disabled May 15, 2026 19:21

Head branch was pushed to by a user without write access

Copy link
Copy Markdown
Contributor

Copilot AI commented May 15, 2026

@copilot resolve conflicts

Conflicts resolved in 2d67f0f. The only conflict was in yarn.lock — the @metamask/ramps-controller entry, where our branch had 13.3.0 and main had 13.3.1. Resolved by keeping our ^13.3.0 descriptor from package.json while adopting 13.3.1 (which satisfies that range) from main.

Copilot AI requested a review from amitabh94 May 15, 2026 19:22
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmations, SmokeIdentity, SmokeNetworkAbstractions, SmokeNetworkExpansion, SmokeSwap, SmokeStake, SmokeWalletPlatform, SmokeMoney, SmokePerps, SmokeMultiChainAPI, SmokePredictions, SmokeSeedlessOnboarding, SmokeBrowser, SmokeSnaps
  • Selected Performance tags: @PerformanceAccountList, @PerformanceOnboarding, @PerformanceLogin, @PerformanceSwaps, @PerformanceLaunch, @PerformanceAssetLoading, @PerformancePredict, @PerformancePreps
  • Risk Level: high
  • AI Confidence: 100%
click to see 🤖 AI reasoning details

E2E Test Selection:
Hard rule (controller-version-update): @MetaMask controller package version updated in package.json: @metamask/ramps-controller. Running all tests.

Performance Test Selection:
Hard rule (controller-version-update): @MetaMask controller package version updated in package.json: @metamask/ramps-controller. Running all tests.

View GitHub Actions results

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size-M team-money-movement issues related to Money Movement features team-ramps

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants