jlcodes99/cockpit-tools · info

[AccountStore] 读取持久化数据失败

Error message

[AccountStore] 读取持久化数据失败: ${name}

What it means

The zustand persist custom storage's getItem wraps localStorage.getItem in try/catch. When reads fail, it warns with the storage key name and returns null so zustand falls back to the initial state instead of crashing store creation.

Solutions

  1. Return null (already done) so the store boots with defaults — verify initial state is sensible
  2. Detect storage availability at startup and switch to an in-memory storage adapter
  3. Ask users to allow site data / exit private mode if persistence matters
  4. Persist to an alternative backend (IndexedDB, Tauri fs) when localStorage is unavailable

Example fix

// before
getItem: (name: string) => {
  try { return localStorage.getItem(name); }
  catch (error) { console.warn(`[AccountStore] 读取持久化数据失败: ${name}`, error); return null; }
}
// after
getItem: (name: string) => {
  try { return localStorage.getItem(name); }
  catch (error) { console.warn(`[AccountStore] 读取持久化数据失败: ${name}`, error); return memoryStore.get(name) ?? null; }
}
Defensive patterns

Strategy: fallback

Validate before calling

function safeGetItem(name: string): string | null {
  try { return localStorage.getItem(name); } catch { return null; }
}

Type guard

function hasStorage(s: unknown): s is Storage {
  try {
    const st = s as Storage;
    const k = '__probe__';
    st.setItem(k, k); st.removeItem(k);
    return true;
  } catch { return false; }
}

Try / catch

getItem: (name: string) => {
  try { return localStorage.getItem(name); }
  catch (error) {
    console.warn(`[AccountStore] 读取持久化数据失败: ${name}`, error);
    return null; // zustand falls back to initial state
  }
}

Prevention

When it happens

Trigger: localStorage.getItem throws on store initialization — storage disabled by browser policy, Safari private mode, security restrictions in embedded webviews, or corrupted storage access after a quota error.

Common situations: App opened in private/incognito browsing; enterprise browsers with third-party storage blocked; webview embedders that disable DOM storage.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/76187109e17ddb7d. Report an issue: GitHub.

Appendix: source

Thrown at src/stores/useAccountStore.ts:52

  setTimeout(() => {
    try {
      localStorage.removeItem(storageKey);
      localStorage.removeItem(LEGACY_ACCOUNTS_CACHE_KEY);
      localStorage.removeItem(LEGACY_CURRENT_ACCOUNT_CACHE_KEY);
    } catch (error) {
      console.warn('[AccountStore] 清理超限缓存失败:', error);
    } finally {
      accountStoreQuotaCleanupScheduled = false;
    }
  }, 0);
}

const accountStoreStorage = createJSONStorage(() => ({
  getItem: (name: string) => {
    try {
      return localStorage.getItem(name);
    } catch (error) {
      console.warn(`[AccountStore] 读取持久化数据失败: ${name}`, error);
      return null;
    }
  },
  setItem: (name: string, value: string) => {
    try {
      localStorage.setItem(name, value);
    } catch (error) {
      if (isQuotaExceededError(error)) {
        if (!accountStoreQuotaWarned) {
          console.warn(
            '[AccountStore] 本地缓存空间不足,已自动清理账号缓存并回退为仅内存态。',
            error
          );
          accountStoreQuotaWarned = true;
        }
        scheduleAccountStoreQuotaRecovery(name);
        return;
      }

View on GitHub (pinned to 1ed8b77992)