This error occurs when attempting to store data using localStorage.setItem() or sessionStorage.setItem() operations that either exceed the available storage quota or when storage is completely unavailable. The error manifests as “Failed to execute ‘setItem’ on ‘Storage’” followed by additional details about quota exceeded errors.

Modern browsers typically report this as “Uncaught QuotaExceededError: Failed to execute ‘setItem’ on ‘Storage’: Setting the value of ‘[key]’ exceeded the quota.” Legacy browsers may show variations like “QuotaExceededError”, “QUOTA_EXCEEDED_ERR”, or “The quota has been exceeded.”

Important: This error is particularly common on iOS and macOS when users browse in private mode, where storage APIs are severely restricted or completely disabled.

The Problem

“Failed to execute ‘setItem’ on ‘Storage’” is thrown when JavaScript attempts to store data using localStorage or sessionStorage APIs but encounters storage limitations. The error occurs in two primary scenarios:

  1. Storage quota exceeded - Attempting to store more data than the browser allows
  2. Private browsing restrictions - Storage APIs disabled or severely limited in private/incognito mode

Different browsers and versions report this error with varying messages:


// Modern browser error format
try {
  localStorage.setItem('large-data', veryLargeString);
} catch (error) {
  // Modern browsers show:
  // "Uncaught QuotaExceededError: Failed to execute 'setItem' on 'Storage':
  //  Setting the value of 'large-data' exceeded the quota."

  console.error('Storage failed:', error.message);
}

Key point: This error can indicate either application logic issues (storing too much data) or browser restrictions (private browsing mode), requiring both better storage management and graceful fallback handling.

Understanding the Root Cause

“Failed to execute ‘setItem’ on ‘Storage’” stems from browser storage policies and user privacy settings:

1. Storage Quota Limits

Technical limitation: Browsers impose storage limits per origin (typically 5-10MB for localStorage, though some browsers allow up to 10MB+ depending on available disk space), meaning each website gets its own separate storage quota to prevent websites from consuming excessive disk space.

How to identify: Error occurs when storing large amounts of data or when storage is nearly full from accumulated data.

2. Private Browsing Mode Restrictions

Privacy feature: Private/incognito browsing modes restrict or disable storage APIs to prevent persistent tracking across sessions. This was particularly severe in older versions of Safari.

How to identify: Errors occur predominantly on older iOS Safari and macOS Safari versions in private mode, even with small data amounts. Modern Safari versions have improved private browsing storage support.

3. Browser Storage Implementation Differences

Different browsers handle storage quotas and private mode differently, leading to varying error messages and behaviors.

How to identify: Error message variations indicate different browser implementations of the same storage restriction.

4. Accumulated Storage Usage

Applications that store data over time may eventually hit storage limits as users accumulate cached data, user preferences, and application state.

How to identify: Errors that increase over time or affect long-term users more than new users.

How to Fix “Failed to execute ‘setItem’ on ‘Storage’”

Quick Troubleshooting Checklist

  • Implement storage availability detection before attempting to store data
  • Add try/catch blocks around all localStorage/sessionStorage operations
  • Test application functionality in private browsing mode
  • Consider reducing data storage requirements
  • Implement storage cleanup for accumulated data

The solution focuses on graceful degradation and proper error handling:

Step 1: Implement Safe Storage Operations

Always check for storage availability and handle errors gracefully:


// Safe storage utility functions
const SafeStorage = {
  // Test if storage is available and functional
  isStorageAvailable(type = 'localStorage') {
    try {
      const storage = window[type];
      const test = '__storage_test__';
      storage.setItem(test, test);
      storage.removeItem(test);
      return true;
    } catch (e) {
      return false;
    }
  },

  // Safe storage setter with error handling
  setItem(key, value, useSession = false) {
    const storageType = useSession ? 'sessionStorage' : 'localStorage';

    if (!this.isStorageAvailable(storageType)) {
      console.warn(`${storageType} not available, using fallback`);
      return this.setFallback(key, value);
    }

    try {
      window[storageType].setItem(key, JSON.stringify(value));
      return true;
    } catch (error) {
      console.warn(`Storage failed for ${key}:`, error.message);

      if (error.name === 'QuotaExceededError' ||
          error.message.includes('Failed to execute') ||
          error.message.includes('setItem') ||
          error.message.includes('quota') ||
          error.message.includes('QUOTA_EXCEEDED')) {
        // Try to free up space and retry
        this.cleanup();
        try {
          window[storageType].setItem(key, JSON.stringify(value));
          return true;
        } catch (retryError) {
          console.warn('Storage retry failed, using fallback');
          return this.setFallback(key, value);
        }
      }

      return this.setFallback(key, value);
    }
  },

  // Safe storage getter
  getItem(key, useSession = false) {
    const storageType = useSession ? 'sessionStorage' : 'localStorage';

    if (!this.isStorageAvailable(storageType)) {
      return this.getFallback(key);
    }

    try {
      const item = window[storageType].getItem(key);
      return item ? JSON.parse(item) : null;
    } catch (error) {
      console.warn(`Failed to get ${key}:`, error.message);
      return this.getFallback(key);
    }
  },

  // In-memory fallback for when storage is unavailable
  fallbackStorage: new Map(),

  setFallback(key, value) {
    this.fallbackStorage.set(key, value);
    return false; // Indicate fallback was used
  },

  getFallback(key) {
    return this.fallbackStorage.get(key) || null;
  },

  // Cleanup old storage items to free space
  cleanup() {
    try {
      // Remove old or less important items
      const keysToRemove = [];
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key.startsWith('temp_') || key.startsWith('cache_')) {
          keysToRemove.push(key);
        }
      }
      keysToRemove.forEach(key => localStorage.removeItem(key));
      console.log(`Cleaned up ${keysToRemove.length} storage items`);
    } catch (error) {
      console.warn('Storage cleanup failed:', error);
    }
  }
};

// Usage examples
SafeStorage.setItem('userPreferences', { theme: 'dark', language: 'en' });
const preferences = SafeStorage.getItem('userPreferences');

Step 2: Implement Storage Management

Manage storage usage to prevent quota issues:


// Storage management utility
const StorageManager = {
  // Check storage usage
  getStorageUsage() {
    let totalSize = 0;
    const items = {};

    try {
      for (let key in localStorage) {
        if (localStorage.hasOwnProperty(key)) {
          const size = localStorage[key].length;
          items[key] = size;
          totalSize += size;
        }
      }
    } catch (error) {
      console.warn('Could not calculate storage usage:', error);
    }

    return {
      totalSize,
      items,
      estimatedQuota: 5 * 1024 * 1024, // 5MB typical limit
      usage: totalSize / (5 * 1024 * 1024)
    };
  },

  // Monitor storage usage
  checkQuota() {
    const usage = this.getStorageUsage();

    if (usage.usage > 0.8) {
      console.warn('Storage usage high:', Math.round(usage.usage * 100) + '%');
      this.suggestCleanup();
    }

    return usage;
  },

  // Suggest cleanup actions
  suggestCleanup() {
    const usage = this.getStorageUsage();
    const largeItems = Object.entries(usage.items)
      .filter(([key, size]) => size > 10000)
      .sort((a, b) => b[1] - a[1]);

    console.log('Large storage items:', largeItems);

    // Auto-cleanup old temporary data
    this.cleanupOldData();
  },

  // Clean up old temporary data
  cleanupOldData() {
    try {
      const now = Date.now();
      const oneWeek = 7 * 24 * 60 * 60 * 1000;

      for (let key in localStorage) {
        if (key.startsWith('cache_') || key.startsWith('temp_')) {
          try {
            const data = JSON.parse(localStorage[key]);
            if (data.timestamp && (now - data.timestamp) > oneWeek) {
              localStorage.removeItem(key);
              console.log('Removed old cache item:', key);
            }
          } catch (e) {
            // If we can't parse it, it might be old - remove it
            localStorage.removeItem(key);
          }
        }
      }
    } catch (error) {
      console.warn('Cleanup failed:', error);
    }
  },

  // Store data with timestamp for cleanup
  storeWithTimestamp(key, data, isTemporary = false) {
    const prefix = isTemporary ? 'temp_' : '';
    const wrappedData = {
      data,
      timestamp: Date.now()
    };

    return SafeStorage.setItem(prefix + key, wrappedData);
  },

  // Initialize storage strategy based on availability
  initializeStorageStrategy() {
    const hasStorage = SafeStorage.isStorageAvailable();

    if (!hasStorage) {
      console.log('Storage unavailable - using memory-only mode');
      return 'memory-only';
    }

    const usage = this.getStorageUsage();
    if (usage.usage > 0.9) {
      console.warn('Storage nearly full - aggressive cleanup mode');
      this.cleanupOldData();
      return 'cleanup-mode';
    }

    return 'normal';
  }
};

// Initialize storage management with no-storage handling
const storageStrategy = StorageManager.initializeStorageStrategy();
setInterval(() => {
  StorageManager.checkQuota();
}, 60000); // Check every minute

Step 3: Configure Error Monitoring

Track storage errors over time. Error monitoring services like TrackJS can help you find out when you need to take action.

Set up monitoring to track QuotaExceededError patterns with additional context and metadata.


// TrackJS configuration for storage setItem errors
TrackJS.install({
  token: 'your-token-here',
  onError: function(payload) {
    // Categorize storage setItem errors for analysis
    const message = payload.message.toLowerCase();
    const isStorageError = message.includes('failed to execute') &&
                          message.includes('setitem') &&
                          message.includes('storage');

    if (isStorageError) {
      // Add context about storage situation
      payload.console.push({
        message: JSON.stringify({
          storageAvailable: StorageManager.isStorageAvailable(),
          storageUsage: StorageManager.getStorageUsage()
        }),
        severity: 'info',
        timestamp: new Date().toISOString()
      });
    }

    return true; // Track storage errors for analysis
  }
});

Step 4: Test Across Browsing Modes

Ensure your application works correctly in various privacy modes:

  1. Test in normal browsing mode
  2. Test in private/incognito mode
  3. Test on iOS Safari (particularly strict)
  4. Test with storage nearly full
  5. Verify fallback functionality works
  6. Check user experience with limited storage

When to Ignore This Error

“Failed to execute ‘setItem’ on ‘Storage’” should typically be handled gracefully rather than ignored, but monitoring noise can be reduced:

  • Expected in private browsing: iOS/macOS Safari users frequently browse privately
  • User choice: Private browsing represents deliberate user privacy preference
  • Technical limitation: Browser storage quotas are intentional resource management
  • Fallback available: If proper fallback mechanisms are implemented

However, investigate further if:

  • High error rates: Significant portion of users affected by storage issues
  • Core functionality broken: Essential features fail when storage is unavailable
  • No fallback handling: Application doesn’t work properly without storage
  • User complaints: Users reporting lost preferences or broken functionality

Summary

“Failed to execute ‘setItem’ on ‘Storage’” occurs when browser storage operations encounter quota limits or when storage is unavailable in private browsing mode. Modern browsers report this with detailed error messages that specify the failed operation and quota exceeded reason.

The solution involves implementing robust error handling, storage availability detection, and graceful fallback mechanisms. Applications should work correctly whether storage is available or not, treating persistent storage as an enhancement rather than a requirement.

Remember: Private browsing and storage quotas are browser features designed to protect user privacy and system resources. Design your application to gracefully handle these limitations rather than treating them as errors to be eliminated.

TrackJS is the easy way to monitor your JavaScript applications and fix production errors. TrackJS is provides detailed error monitoring and alerting to developers around the world at companies like 3M, Tidal, IKEA, Venmo, Allbirds, and Frontend Masters. TrackJS catches millions of errors from users everyday. Let's start catching yours.

Protect your JavaScript