{"record":{"id":"050d396f7f8e7e54","repo":"koala73/worldmonitor","slug":"telegram-watchlist-could-not-be-saved","errorCode":null,"errorMessage":"Telegram watchlist could not be saved","messagePattern":"Telegram watchlist could not be saved","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/telegram-watchlist.ts","lineNumber":89,"sourceCode":"\nexport function getTelegramWatchlistEntries(): TelegramWatchlistEntry[] {\n  try {\n    const parsed = safeParseJson<unknown>(localStorage.getItem(STORAGE_KEY));\n    if (!Array.isArray(parsed)) return [];\n\n    return normalizeEntries(parsed);\n  } catch {\n    return [];\n  }\n}\n\nexport function setTelegramWatchlistEntries(entries: TelegramWatchlistEntry[]): TelegramWatchlistEntry[] {\n  const next = normalizeEntries(entries || []);\n\n  try {\n    localStorage.setItem(STORAGE_KEY, JSON.stringify(next));\n  } catch {\n    throw new Error('Telegram watchlist could not be saved');\n  }\n\n  dispatch(next);\n  return next;\n}\n\nexport function addTelegramWatchlistEntry(entry: TelegramWatchlistEntry): TelegramWatchlistEntry[] {\n  const normalized = coerceEntry(entry);\n  if (!normalized) return getTelegramWatchlistEntries();\n\n  const current = getTelegramWatchlistEntries();\n  const existing = current.findIndex(item => item.username === normalized.username);\n  if (existing >= 0) {\n    const existingEntry = current[existing];\n    if (!existingEntry) return current;\n    current[existing] = normalized.title\n      ? { username: existingEntry.username, title: normalized.title }\n      : existingEntry;","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/src/services/telegram-watchlist.ts#L71-L107","documentation":"setTelegramWatchlistEntries serializes the normalized entry list and writes it to localStorage under STORAGE_KEY; any storage failure (quota exceeded, private-browsing restrictions, storage disabled or evicted) is caught and rethrown as 'Telegram watchlist could not be saved'. Persistence failed, so the in-memory dispatch is skipped and the caller knows the list was not saved.","triggerScenarios":"Calling setTelegramWatchlistEntries (directly or via addTelegramWatchlistEntry/removeTelegramWatchlistEntry) when localStorage.setItem throws: quota exceeded (QuotaExceededError), Safari private mode, storage disabled by browser policy, or a page origin with storage partitioned away.","commonSituations":"Users in private/incognito browsing with storage blocked; localStorage full from other app data; embedded webviews or strict privacy settings disabling storage; corporate browsers with site-data restrictions.","solutions":["Wrap watchlist writes in try/catch and keep an in-memory list so the UI still works for the session when persistence fails.","Check storage availability up front (probe localStorage with a test write) and switch to a memory-only mode with a 'not persisted' notice.","Free quota by pruning other localStorage keys or trimming watchlist entries (e.g. drop unused preview caches) before retrying.","Offer an export/import (JSON download) fallback so users on restricted browsers don't lose their watchlist."],"exampleFix":"// before\naddTelegramWatchlistEntry(entry); // throws when storage is blocked\n// after\ntry {\n  addTelegramWatchlistEntry(entry);\n} catch {\n  memoryWatchlist.push(entry);\n  showToast('Watchlist saved for this session only (storage unavailable)');\n}","handlingStrategy":"try-catch","validationCode":"function storageAvailable(): boolean {\n  try {\n    const k = '__wm_probe__';\n    localStorage.setItem(k, '1');\n    localStorage.removeItem(k);\n    return true;\n  } catch {\n    return false;\n  }\n}\n","typeGuard":null,"tryCatchPattern":"try {\n  setTelegramWatchlistEntries(next);\n} catch {\n  memoryWatchlist = next; // session-only fallback\n  showToast('Storage unavailable — watchlist kept for this session only');\n}\n","preventionTips":["Probe localStorage availability at boot and switch to memory-only mode when blocked","Keep an in-memory mirror of the watchlist so UI actions survive storage failures","Watch for QuotaExceededError and prune stale keys before giving up","Offer JSON export/import so users on restricted browsers can preserve their watchlist"],"tags":["localstorage","persistence","quota-exceeded","watchlist"],"backgroundTag":"localstorage-write-failed","analyzedSha":"9361220cc013571781071f0206e4d80fd14b2f7f","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}