jlcodes99/cockpit-tools · warning
Failed to save active page to localStorage:
Error message
Failed to save active page to localStorage:
What it means
MainApp persists the currently active page to localStorage under ACTIVE_PAGE_STORAGE_KEY inside a useEffect. If the setItem/removeItem call throws — most commonly because localStorage is unavailable — the catch logs this warning and the page still switches in memory, but the preference is not remembered across restarts.
Source
Thrown at src/App.tsx:802
memory.dismissed[USER_MEMORY_FLAGS.classicSwitchPrompt] ||
store.hideClassicSwitchPrompt
) {
store.setHideClassicSwitchPrompt(true);
}
});
}, []);
useEffect(() => {
try {
const normalized = normalizeStoredActivePage(page);
if (normalized) {
localStorage.setItem(ACTIVE_PAGE_STORAGE_KEY, normalized);
} else {
localStorage.removeItem(ACTIVE_PAGE_STORAGE_KEY);
setPage('dashboard');
}
} catch (e) {
console.warn('Failed to save active page to localStorage:', e);
}
}, [page]);
// 冷启动:若设置了固定启动页,则覆盖 localStorage 中的上次页面
useEffect(() => {
let disposed = false;
const applyStartupPagePreference = async () => {
try {
const config = await invoke<{ startup_page?: string }>('get_general_config');
if (disposed) {
return;
}
const preferred = normalizeStartupPagePreference(config.startup_page);
if (preferred !== 'last') {
setPage(preferred);
}
} catch (error) {
console.warn('Failed to apply startup page preference:', error);View on GitHub (pinned to 1ed8b77992)
Solutions
- Check the logged `e` — QuotaExceededError means free up/clear stale localStorage keys; SecurityError means storage is blocked.
- Verify the WebView/browser isn't in private mode or blocking third-party storage.
- Wrap the persistence in a safe wrapper that feature-detects storage availability.
- Clear app localStorage data if the quota is full.
Example fix
// before
try {
localStorage.setItem(ACTIVE_PAGE_STORAGE_KEY, normalized);
} catch (e) {
console.warn('Failed to save active page to localStorage:', e);
}
// after
// guard before writing
const storageAvailable = (() => {
try { localStorage.setItem('__t', '1'); localStorage.removeItem('__t'); return true; }
catch { return false; }
})();
if (storageAvailable) localStorage.setItem(ACTIVE_PAGE_STORAGE_KEY, normalized); Defensive patterns
Strategy: fallback
Validate before calling
const canUseLocalStorage = (() => {
try {
const k = '__probe__';
localStorage.setItem(k, '1');
localStorage.removeItem(k);
return true;
} catch {
return false;
}
})();
Type guard
function storageGet(key: string): string | null {
try { return localStorage.getItem(key); } catch { return null; }
}
Try / catch
try {
localStorage.setItem(ACTIVE_PAGE_STORAGE_KEY, normalized);
} catch (e) {
console.warn('Failed to save active page to localStorage:', e);
inMemoryActivePage = normalized; // in-memory fallback
} Prevention
- Feature-detect localStorage at app bootstrap and keep an in-memory fallback
- Keep localStorage payload small to avoid QuotaExceededError
- Never treat storage write failures as fatal — page state is non-critical
- Avoid private-mode assumptions; test in incognito and restricted WebViews
When it happens
Trigger: Changing pages when localStorage is unavailable: browser/WebView storage disabled or full, running in a private/incognito context with storage blocked, a storage quota exceeded, or security policy (opaque origin / file:// context) blocking access.
Common situations: Tauri WebView with storage partition disabled, QuotaExceededError after lots of stored data, Safari private mode (older WebKit throws on setItem), or tests/iframes with opaque origins.
Related errors
- [TraeAutoCheckin] 保存自动签到日志失败:
- [AccountStore] 本地缓存空间不足,已自动清理账号缓存并回退为仅内存态。
- [TraeAutoCheckin] 保存配置失败:
- [WorkbuddyAutoCheckin] 本地缓存保存失败:
- [AccountStore] 清理超限缓存失败:
AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05).
Data as JSON: /api/errors/317063837cfa75a6.
Report an issue: GitHub.