GrapesJS/grapesjs · error
localStorage not available
Error message
localStorage not available
What it means
The LocalStorage storage manager checks that `window` and `localStorage` exist (when `checkLocal` is enabled). If storage is unavailable — no browser window, storage disabled/blocked, or restricted environments — `hasLocal(opts, true)` throws 'localStorage not available', causing store/load to fail.
Source
Thrown at packages/core/src/storage_manager/model/LocalStorage.ts:38
if (this.hasLocal(opts, true)) {
localStorage.setItem(opts.key!, JSON.stringify(data));
}
return data;
}
async load(opts: LocalStorageConfig = {}) {
let result = {};
if (this.hasLocal(opts, true)) {
result = JSON.parse(localStorage.getItem(opts.key!) || '{}');
}
return result;
}
hasLocal(opts: LocalStorageConfig = {}, thr?: boolean) {
if (opts.checkLocal && (!hasWin() || !localStorage)) {
if (thr) throw new Error('localStorage not available');
return false;
}
return true;
}
}
View on GitHub (pinned to 2bdeda85b8)
Solutions
- Use a different storage type, e.g. `storageManager: { type: 'remote' }` with proper settings, or disable autosave.
- Set `checkLocal: false` in LocalStorage options if you know storage exists or want graceful fallback.
- Polyfill/stub localStorage in non-browser or test environments (e.g. node-localstorage, jsdom setup).
- Implement a custom storage manager for restricted environments.
Example fix
// before
storageManager: { type: 'local', options: { checkLocal: true } }
// after
storageManager: { type: 'local', options: { checkLocal: false } }
// or polyfill in Node/jsdom:
// global.localStorage = new LocalStorage('./scratch'); Defensive patterns
Strategy: fallback
Validate before calling
function localStorageAvailable() {
try {
const k = '__test__';
window.localStorage.setItem(k, k);
window.localStorage.removeItem(k);
return true;
} catch { return false; }
}
const storageType = localStorageAvailable() ? 'local' : 'remote'; Type guard
function hasLocalStorage(): boolean {
try { return typeof window !== 'undefined' && !!window.localStorage; } catch { return false; }
} Try / catch
try {
await editor.store();
} catch (err) {
if (err.message === 'localStorage not available') {
// switch to remote storage or skip persistence
console.warn('Persistence skipped: localStorage unavailable');
} else throw err;
} Prevention
- Probe localStorage availability at app startup and choose storageManager.type accordingly
- Set checkLocal:false only when you have independently verified storage
- Polyfill localStorage in SSR/tests (node-localstorage, jsdom)
- Avoid sandboxed iframes with blocked storage for editors that persist locally
When it happens
Trigger: Using `storageManager: { type: 'local' }` with `checkLocal: true` in an environment without localStorage: SSR/Node, webviews with storage disabled, iframes with blocked third-party storage, Safari private mode in old versions, or `localStorage` shadowed/undefined.
Common situations: Server-side rendering of the editor, loading GrapesJS inside sandboxed iframes, privacy modes or browser settings disabling site data, automated tests in jsdom without localStorage polyfill.
AI-assisted analysis of GrapesJS/grapesjs@2bdeda85b8 (2026-08-30).
Data as JSON: /api/errors/cc11fba7d38171b0.
Report an issue: GitHub.