{"record":{"id":"5dfbb097ec0f7d51","repo":"actualbudget/actual","slug":"persistent-storage-request-failed","errorCode":null,"errorMessage":"Persistent storage request failed:","messagePattern":"Persistent storage request failed:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/desktop-client/src/browser-preload.js","lineNumber":76,"sourceCode":"    isOpenIdCallback,\n});\n\n// Ask the browser to exclude this origin's storage (the local budget database\n// in IndexedDB) from automatic eviction under storage pressure. Without this,\n// the browser is allowed to silently delete all local data, forcing a full\n// re-download of the budget and losing any changes not yet synced.\nif (navigator.storage?.persist) {\n  void navigator.storage\n    .persist()\n    .then(persisted => {\n      if (!persisted) {\n        console.warn(\n          'Persistent storage was not granted; the browser may evict local budget data under storage pressure.',\n        );\n      }\n    })\n    .catch(error => {\n      console.warn('Persistent storage request failed:', error);\n    });\n}\n\nlet isUpdateReadyForDownload = false;\nlet markUpdateReadyForDownload;\nconst isUpdateReadyForDownloadPromise = new Promise(resolve => {\n  markUpdateReadyForDownload = () => {\n    isUpdateReadyForDownload = true;\n    resolve(true);\n  };\n});\n// Skip SW registration in dev so stale cached assets don't override edits\n// between page loads. Plugin code that needs a SW can register one itself.\n// In dev there is no SW to install, so applyAppUpdate() can't rely on the\n// SW lifecycle to swap the page — fall back to a plain reload so callers\n// don't hang on the never-resolving promise inside applyAppUpdate.\nconst updateSW = IS_DEV\n  ? () => window.location.reload()","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/browser-preload.js#L58-L94","documentation":"A console.warn emitted in packages/desktop-client/src/browser-preload.js when the navigator.storage.persist() promise rejects. The browser refused or failed the persistent-storage request, meaning local budget data (IndexedDB/OPFS) may be evicted under storage pressure. It is logged, not thrown — the app continues without persistence guarantees.","triggerScenarios":"Calling navigator.storage.persist() during web app boot and the promise rejecting — typically only in browsers lacking the StorageManager API or when the call is rejected outright (as opposed to resolving to false).","commonSituations":"Running Actual in an embedded/older browser without StorageManager; insecure (non-HTTPS) origins where the API may be unavailable; privacy modes blocking storage APIs; Safari Private Browsing.","solutions":["Serve the app over HTTPS so StorageManager APIs are available","Update to a modern browser that supports navigator.storage.persist()","Check storage.persisted() and warn users to install the app / export budgets regularly","Accept degraded behavior — data may be evicted under disk pressure; enable regular backups"],"exampleFix":"// before\nif (!isSecureContext) { /* API missing, warns every load */ }\n// after\nif ('storage' in navigator && typeof navigator.storage.persist === 'function') {\n  await navigator.storage.persist();\n}","handlingStrategy":"fallback","validationCode":"const canPersist = 'storage' in navigator && typeof navigator.storage.persist === 'function';","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Serve over HTTPS so StorageManager APIs are available","Monitor navigator.storage.persisted() after boot and surface a user warning","Encourage users to install the PWA or export budgets for durability","Treat this as a logged degradation, not a fatal error"],"tags":["browser","storage","persistence"],"backgroundTag":"persistent-storage-denied","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}