Skip to content

fix: gracefully handle dismissed interface errors in background jobs#589

Open
ulissesferreira wants to merge 2 commits into
mainfrom
NEB-376/graceful-interface-error-handling
Open

fix: gracefully handle dismissed interface errors in background jobs#589
ulissesferreira wants to merge 2 commits into
mainfrom
NEB-376/graceful-interface-error-handling

Conversation

@ulissesferreira

@ulissesferreira ulissesferreira commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Summary

When users dismiss confirmation dialogs (click outside, press escape, or close them), background operations like price refreshes and security scans may still be running. These operations would try to update or read from the dismissed interface, causing noisy "Interface not found" errors in the logs.

This PR implements graceful error handling by adding *IfExists variants of interface methods that return null instead of throwing when an interface has been dismissed.

Changes

New Methods in interface.ts

Method Behavior Use Case
isInterfaceNotFoundError(error) Detects "interface not found" errors Error classification helper
getInterfaceContextIfExists(id) Returns context or null if dismissed Replaces getInterfaceContext
updateInterfaceIfExists(id, ui, ctx) Returns result or null if dismissed For background/async operations

Naming Convention

  • Methods with *IfExists suffix explicitly indicate they swallow "interface not found" errors
  • Original updateInterface is kept for event handlers where the interface must exist
  • Removed unused getInterfaceContextOrThrow function

Background Jobs Updated

  • refreshSend.tsx - Token price refresh (every 30s)
  • refreshConfirmationEstimation.tsx - Security scan refresh (every 20s)
  • buildTransactionMessageAndUpdateInterface.tsx - Transaction building

These now:

  1. Use *IfExists methods for defensive error handling
  2. Clean up state (mapInterfaceNameToId) when interface is dismissed
  3. Log informational messages instead of warnings for expected dismissals

Test Plan

  • All core tests pass (yarn test:core)
  • All feature tests pass (yarn test:features)
  • New unit tests for isInterfaceNotFoundError, getInterfaceContextIfExists, and updateInterfaceIfExists
  • Manual test: Open Send form, dismiss quickly during price refresh - no error logs
  • Manual test: Open confirmation dialog, dismiss during security scan - no error logs

Note

Medium Risk
Touches shared interface utilities and multiple async UI/background update paths; mistakes could cause silent UI non-updates or stale mapInterfaceNameToId entries, but changes are localized to handling dismissed interfaces.

Overview
Prevents noisy "Interface not found" errors when users dismiss dialogs while async work is still running by adding isInterfaceNotFoundError, getInterfaceContextIfExists, and updateInterfaceIfExists to swallow dismissed-interface failures.

Updates the send and confirmation refresh cronjobs and related UI render/update flows to use the new *IfExists helpers, early-exit when the UI is gone, and proactively clean mapInterfaceNameToId state entries; includes new unit coverage for the interface helpers and a manifest shasum/changelog bump.

Written by Cursor Bugbot for commit 2bcf508. This will update automatically on new commits. Configure here.

@ulissesferreira ulissesferreira force-pushed the NEB-376/graceful-interface-error-handling branch from 65c22ad to 5b54030 Compare March 5, 2026 12:37
@ulissesferreira ulissesferreira requested a review from a team as a code owner March 5, 2026 12:37
Comment thread packages/snap/src/core/handlers/onCronjob/backgroundEvents/refreshSend.tsx Outdated
@ulissesferreira ulissesferreira force-pushed the NEB-376/graceful-interface-error-handling branch from 5b54030 to 530485d Compare March 5, 2026 13:42
Comment thread packages/snap/src/core/handlers/onCronjob/backgroundEvents/refreshSend.tsx Outdated
@ulissesferreira ulissesferreira force-pushed the NEB-376/graceful-interface-error-handling branch from 530485d to 5209704 Compare March 5, 2026 15:56
@sonarqubecloud

sonarqubecloud Bot commented Mar 5, 2026

Copy link
Copy Markdown

@ulissesferreira ulissesferreira force-pushed the NEB-376/graceful-interface-error-handling branch from 5209704 to debd97e Compare March 5, 2026 17:29
Add `*IfExists` variants of interface methods that return null instead of
throwing when an interface has been dismissed by the user:

- Add `isInterfaceNotFoundError` helper to detect interface not found errors
- Rename `getInterfaceContext` to `getInterfaceContextIfExists` with error handling
- Add `updateInterfaceIfExists` for defensive updates in async operations
- Remove unused `getInterfaceContextOrThrow` function
- Update background jobs to use new methods and clean up state on dismissal
- Add unit tests for the new error handling behavior

This prevents noisy error logs when users dismiss confirmation dialogs while
background operations (price refreshes, security scans) are still running.
@ulissesferreira ulissesferreira force-pushed the NEB-376/graceful-interface-error-handling branch from debd97e to 74cd0c1 Compare March 5, 2026 17:31
@ulissesferreira ulissesferreira force-pushed the NEB-376/graceful-interface-error-handling branch from 74cd0c1 to 2bcf508 Compare March 5, 2026 17:44

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

if (currentMap[SEND_FORM_INTERFACE_NAME] === interfaceId) {
await state.deleteKey(`mapInterfaceNameToId.${SEND_FORM_INTERFACE_NAME}`);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated deleteInterfaceIdIfCurrent helper across two files

Low Severity

deleteInterfaceIdIfCurrent is defined as a near-identical local function in both refreshSend.tsx and refreshConfirmationEstimation.tsx. The only difference is the interface name constant used. This could be a single shared utility in interface.ts that accepts the interface name as a parameter, reducing duplication and ensuring consistent cleanup behavior across background jobs.

Additional Locations (1)

Fix in Cursor Fix in Web

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant