Commit a200b56
authored
feat: add/improve Sentry instrumentation for storage related error handling (#39113)
## Description
This PR is a follow-up PR for
#39010
It adds Sentry instrumentation to monitor storage-related errors and
enables error reporting even during database corruption scenarios.
### Context
Firefox users occasionally experience database corruption that prevents
MetaMask from reading or writing to `storage.local`. This manifests as
`"Error: An unexpected error occurred"`. We have workarounds in place
(vault recovery flow, storage error toast), but we lacked visibility
into how often these occur in production.
### Changes
### 1. Added Sentry Tags and Fingerprints
- Added `persistence.error` tags to `captureException` calls:
- `get-failed` - when `storage.local.get()` fails
- `set-failed` - when `storage.local.set()` fails
- `persist-failed` - when IndexedDB backup fails
- `backup-db-open-failed` - when backup database can't be opened
- Added custom fingerprints to prevent Sentry's deduplication from
dropping events with the same underlying error message (e.g., Firefox's
generic "An unexpected error occurred")
### 2. Enabled Sentry Reporting During Storage Corruption
- Added `MetaMetricsController` to the list of backed-up controllers in
IndexedDB
- Added `getBackupState` hook to allow Sentry to check MetaMetrics
consent from backup when primary storage is unavailable
- This ensures we can report errors to Sentry even during database
corruption scenarios (when primary storage is unreadable)
### 3. Added Recovery Tracking for Temporary Failures
- Added `captureMessage` calls to track when storage operations recover
after a temporary failure:
- `set-recovered` - when `storage.local.set()` succeeds after a previous
failure
- `persist-recovered` - when IndexedDB backup succeeds after a previous
failure
- This helps answer the question: "Do set calls ever fail and then
succeed in the same session?"
- Uses `persistence.event` tag (vs `persistence.error`) to distinguish
recovery events from error events
### 4. Fixed State Persistence in Backup Code Path
- Fixed bug where backup code wrote unfiltered controller state
(including non-persistent properties like
`KeyringController.encryptionKey`) to storage
- Now uses `deriveStateFromMetadata()` to filter to only `persist: true`
properties, matching the normal `stateChange` behavior
## **Changelog**
CHANGELOG entry: Adds Sentry instrumentation to monitor storage-related
errors and enables error reporting even during database corruption
scenarios.
## **Related issues**
None
## **Manual testing steps**
Same as in this PR:
#39010
## **Screenshots/Recordings**
### **Before**
Nothing visible in Sentry
### **After**
<img width="1426" height="328" alt="Screenshot 2026-01-08 at 22 24 27"
src="https://github.com/user-attachments/assets/eee8d9fd-2fb6-40f3-9268-5c267a4028dd"
/>
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **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.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Sentry instrumentation & recovery**
>
> - Add `persistence.error` tags and custom fingerprints to
`captureException` for storage paths: `get-failed`, `set-failed`,
`set-backup-failed`, `persist-failed`, `persist-backup-failed`, and
`backup-db-open-failed`.
> - Emit `captureMessage` recovery signals with `persistence.event`
tags: `set-recovered` and `persist-recovered` when writes/backups
succeed after a prior failure.
> - Log & Sentry-capture `storage.local.get` errors without immediately
throwing; throw `PersistenceError` with backup payload when vault is
missing and a backup exists.
>
> **Backup & consent fallback**
>
> - Add `MetaMetricsController` to `backedUpStateKeys` and `Backup`;
update `getBackup()` accordingly.
> - In `background.js` split-state `stateChange`, use
`deriveStateFromMetadata(..., 'persist')` to only back up persistent
controller fields; throw if metadata missing.
> - New `stateHooks.getBackupState()` to read IndexedDB backup;
`setupSentry.getMetaMetricsEnabled` falls back to backup state when
primary storage retrieval fails; add
`getMetaMetricsEnabledFromBackupState`.
>
> **PersistenceManager robustness**
>
> - Differentiate storage.local vs IndexedDB backup failures; add Sentry
tags/fingerprints per failure type and recovery notifications; notify UI
via `setOnSetFailed` when writes fail.
> - Handle Firefox private-browsing IndexedDB `InvalidStateError` with
tagged Sentry capture and graceful degradation.
>
> **Tests**
>
> - Update `persistence-manager.test.ts` to verify new
tags/fingerprints, recovery `captureMessage` events, backup DB open
error handling, and repeated failure/success behavior.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1ca4d4d. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent 3cc11bc commit a200b56
File tree
4 files changed
+177
-19
lines changed- app/scripts/lib
- stores
4 files changed
+177
-19
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
30 | 40 | | |
31 | 41 | | |
32 | 42 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
205 | 205 | | |
206 | 206 | | |
207 | 207 | | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
208 | 218 | | |
209 | 219 | | |
210 | 220 | | |
| |||
265 | 275 | | |
266 | 276 | | |
267 | 277 | | |
268 | | - | |
269 | | - | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
270 | 287 | | |
271 | 288 | | |
272 | 289 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
7 | 10 | | |
8 | 11 | | |
9 | 12 | | |
| |||
32 | 35 | | |
33 | 36 | | |
34 | 37 | | |
| 38 | + | |
35 | 39 | | |
36 | 40 | | |
| 41 | + | |
37 | 42 | | |
38 | 43 | | |
39 | 44 | | |
| |||
78 | 83 | | |
79 | 84 | | |
80 | 85 | | |
81 | | - | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
82 | 90 | | |
83 | 91 | | |
84 | 92 | | |
| |||
116 | 124 | | |
117 | 125 | | |
118 | 126 | | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
119 | 164 | | |
120 | 165 | | |
121 | 166 | | |
| |||
264 | 309 | | |
265 | 310 | | |
266 | 311 | | |
267 | | - | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
268 | 316 | | |
269 | 317 | | |
270 | 318 | | |
| |||
423 | 471 | | |
424 | 472 | | |
425 | 473 | | |
426 | | - | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
427 | 478 | | |
428 | 479 | | |
429 | 480 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
5 | 8 | | |
6 | 9 | | |
7 | 10 | | |
| |||
22 | 25 | | |
23 | 26 | | |
24 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
25 | 31 | | |
26 | 32 | | |
27 | 33 | | |
28 | 34 | | |
29 | 35 | | |
30 | 36 | | |
| 37 | + | |
31 | 38 | | |
32 | 39 | | |
33 | 40 | | |
| |||
237 | 244 | | |
238 | 245 | | |
239 | 246 | | |
240 | | - | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
241 | 254 | | |
242 | 255 | | |
243 | 256 | | |
| |||
326 | 339 | | |
327 | 340 | | |
328 | 341 | | |
| 342 | + | |
| 343 | + | |
329 | 344 | | |
330 | 345 | | |
331 | 346 | | |
| |||
339 | 354 | | |
340 | 355 | | |
341 | 356 | | |
342 | | - | |
343 | | - | |
344 | | - | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
345 | 366 | | |
346 | 367 | | |
347 | 368 | | |
348 | 369 | | |
349 | 370 | | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
350 | 381 | | |
351 | 382 | | |
352 | 383 | | |
353 | 384 | | |
354 | | - | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
355 | 395 | | |
356 | 396 | | |
357 | 397 | | |
| |||
413 | 453 | | |
414 | 454 | | |
415 | 455 | | |
| 456 | + | |
| 457 | + | |
416 | 458 | | |
417 | 459 | | |
418 | 460 | | |
| |||
441 | 483 | | |
442 | 484 | | |
443 | 485 | | |
444 | | - | |
445 | | - | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
446 | 494 | | |
447 | 495 | | |
448 | 496 | | |
449 | 497 | | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
450 | 508 | | |
451 | 509 | | |
452 | 510 | | |
453 | 511 | | |
454 | | - | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
455 | 524 | | |
456 | 525 | | |
457 | 526 | | |
| |||
493 | 562 | | |
494 | 563 | | |
495 | 564 | | |
496 | | - | |
| 565 | + | |
497 | 566 | | |
498 | 567 | | |
499 | 568 | | |
500 | 569 | | |
501 | 570 | | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
502 | 578 | | |
503 | 579 | | |
504 | 580 | | |
| |||
601 | 677 | | |
602 | 678 | | |
603 | 679 | | |
604 | | - | |
605 | | - | |
606 | | - | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
607 | 686 | | |
608 | 687 | | |
609 | 688 | | |
| 689 | + | |
610 | 690 | | |
611 | 691 | | |
612 | 692 | | |
| |||
0 commit comments