Explain Codes LogoExplain Codes Logo

Html5 localStorage error with Safari: "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage that exceeded the quota."

html
localStorage
safari
storage-quota
Alex KataevbyAlex Kataev·Nov 26, 2024
TLDR

When dealing with QUOTA_EXCEEDED_ERR on Safari's localStorage, you're probably in private mode with storage bounds much lower. Bypass the issue by setting an item and catching the coasting error:

try { //We're testing. Like a guinea pig with a lab coat. localStorage.setItem('test', 'data'); } catch (e) { if (e.code === 22) { // Storage choked or private browsing alert('Saving failed: Storage is bursting or in private mode.'); } }

Guard your storage action, ping your users when things go south. Keep it slick and user-pleasing!

Unraveling localStorage curiosities

Browsers play by different rules

Despite enjoying universality, localStorage acts differently across browsers. Private Safari keeps the quota so low that a tiny item can pop a QUOTA_EXCEEDED_ERR.

Catching private browsing

Privacy mode is elusive, but adding an item in localStorage can spill the beans. Wrap testing in a function (isLocalStorageNameSupported()), ensuring secure data storage:

function isLocalStorageNameSupported() { var testKey = 'test', storage = window.localStorage; try { //Light the beacons! storage.setItem(testKey, '1'); //Cool, now turn it off. storage.removeItem(testKey); return true; } catch (error) { //Houston, we have a problem. return false; } }

A false return should alert you not to use localStorage for data storage.

Plan B for storage

When localStorage is a no-go-zone (like in private browsing), alternatives like sessionStorage should be handy. It provides a similar API, session-specific, and avoids quota limitations in private browsing.

Advanced handling methodologies

Rolling your own storage shepherd

For a one-size-fits-all solution, forge a custom storage handler class. Using feature detection (akin to Modernizr), it decides whether to use localStorage, sessionStorage, or fallback options like cookies:

class StorageHandler { constructor() { //Choosing weapons for the battlefield. this.storage = this.pickStorage(); } pickStorage() { if (isLocalStorageNameSupported()) { return localStorage; } else if (window.sessionStorage) { return sessionStorage; } else { //Choose your fallback weapon. } } setItem(key, data) { try { //Harry up, Potter! We're going to miss the Hogwarts train! this.storage.setItem(key, data); } catch (e) { //Houston, there's something in the mist! } } //Don't forget the getItem and removeItem methods. }

Stalking Safari updates

Monitoring Safari's version slips can save you since they sometimes tweak storage policies. Release gossip and specific code changes like r215315 can give you a hint about the new behaviors or fixes, like in Safari 11.

Catching exceptions globally

If you're not into custom classes, a globally positioned shim that swallows exceptions thrown by localStorage during private browsing should be your gig:

(function() { //Shhh...Overwrite localStorage.setItem for Safari Private Browsing var originalSetItem = Storage.prototype.setItem; Storage.prototype.setItem = function(key, value) { try { //This is the code that Gotham deserves, but not the one it needs right now. originalSetItem.call(this, key, value); } catch (e) { if (e.code === 22) { //Let it go or handle it over a cup of coffee. } } }; })();

In-depth insights and problem-solving

Confirming storage quota

Stay ahead of errors: vigorously validate your storage status, calculating present and planned usage.

Bringing in shims and polyfills

To achieve consistency across browsers, employ shims and polyfills. They buffer environment-specific behaviours, delivering functional consistency.

Watching for behavior variations

Different Safari versions may have varying reactions. On the roll-out of an iOS or Safari update, run a quick test and make necessary adjustments in storage handling.