{"record":{"id":"8b52767163351d8a","repo":"odysseus-dev/odysseus","slug":"data-error-8b5276","errorCode":null,"errorMessage":"data.error","messagePattern":"data\\.error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/emailLibrary.js","lineNumber":4803,"sourceCode":"            grid.classList.remove('email-lib-just-opened');\n            paintData(fastData);\n            paintedExisting = true;\n            if (!force) return;\n          }\n        } catch (_) {\n          // Cold index miss/timeout: leave the spinner and continue to IMAP.\n        } finally {\n          clearTimeout(timer);\n        }\n      }\n      // `&_=Date.now()` bypasses the server's 8s list cache. Default\n      // opens omit it so rapid close/reopen returns instantly; the\n      // Refresh button passes `force: true` to add it back.\n      const buster = force ? `&_=${Date.now()}` : '';\n      const res = await fetch(`${API_BASE}/api/email/list?folder=${encodeURIComponent(folderAtStart)}${accountQS}&limit=${_LIB_INITIAL_PAGE_SIZE}&offset=${offsetAtStart}&filter=${filterAtStart}${attQS}${buster}`);\n      const data = await res.json();\n      if (seq !== _libLoadSeq || accountAtStart !== (state._libAccountId || '')) return;\n      if (data.error) throw new Error(data.error);\n      const sync = data.sync || {};\n      if (sp) sp.destroy();\n      paintData({ emails: data.emails || [], total: data.total || 0, sync });\n      if (filterAtStart === 'unread') {\n        _refreshUnreadBadge({ unreadCountOverride: data.total || 0 });\n      } else {\n        _refreshUnreadBadge();\n        _refreshAccountUnreadHighlights().catch(() => {});\n      }\n    }\n  } catch (e) {\n    if (seq !== _libLoadSeq || accountAtStart !== (state._libAccountId || '')) return;\n    if (sp) sp.destroy();\n    // If we already painted the cached list, leave it on screen — beats\n    // wiping it for \"Failed to load\" when there's still readable content.\n    if (!paintedExisting) {\n      const msg = e && e.message ? `Failed to load: ${e.message}` : 'Failed to load';\n      grid.innerHTML = `<div class=\"email-loading\">${_esc(msg)}${_emailSetupHintHtml()}</div>`;","sourceCodeStart":4785,"sourceCodeEnd":4821,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/emailLibrary.js#L4785-L4821","documentation":"Thrown in the email library's paginated list loader when GET /api/email/list returns a body with an error field. Distinctive context: a sequence guard (seq !== _libLoadSeq) already cancels stale responses, so seeing this means the request is current and the server genuinely reported a mailbox failure.","triggerScenarios":"Opening the library, paging, filtering, or pressing Refresh (which adds &_=Date.now() to bust the 8s server cache) when the IMAP fetch fails: expired credentials, provider outage, folder select error, or an account_id that no longer exists. Cold-index spinner/timeout path deliberately falls through to IMAP, so this is the authoritative call failing.","commonSituations":"OAuth token expiry mid-session; huge folder timing out server-side; account deleted from settings while the library was open; server's 8s cache serving an error payload from a prior failed sync.","solutions":["Read data.error for the server's reason (usually account/folder + IMAP detail)","Re-authenticate or re-add the email account in settings","Retry with the Refresh button (cache-busting _) once the provider is healthy","If a specific folder always fails, open it less or fix its server-side select error"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isLibListOk(d) { return d != null && !d.error && Array.isArray(d.emails); }","tryCatchPattern":"try { const data = await res.json(); if (seq !== _libLoadSeq || accountAtStart !== (state._libAccountId || '')) return; if (data.error) throw new Error(data.error); ... } catch (e) { if (seq !== _libLoadSeq) return; /* render error, keep spinner handling */ }","preventionTips":["Keep the sequence guard on both success and error paths so stale errors never paint","Retry with the cache-busting &_= param after provider outages","Re-auth accounts proactively when error strings mention credentials","Let the cold-index spinner fall through to IMAP as coded — don't error on cache misses"],"tags":["email","imap","fetch","pagination","error-in-body","stale-guard"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}