{"record":{"id":"7d1974a22584a318","repo":"moeru-ai/airi","slug":"chat-session-loadsession-failed-for","errorCode":null,"errorMessage":"[chat-session] loadSession failed for","messagePattern":"\\[chat-session\\] loadSession failed for","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/stores/chat/session-store.ts","lineNumber":435,"sourceCode":"            refreshActiveSessionSystemMessage()\n        }\n\n        // Local and cloud hydration are separate. A failed cloud pull leaves\n        // the local view usable and keeps the next selection eligible to retry.\n        if (needsCloudHydration())\n          await pullCloudMessages(sessionId)\n\n        // Missing IDB payloads still need a valid canonical conversation.\n        // This action runs in the elected leader, so the initialized history\n        // is published once rather than independently by every follower.\n        ensureSession(sessionId)\n\n        return true\n      }\n      catch (err) {\n        // Do NOT add to loadedSessions on failure — the next call should\n        // retry rather than fast-return on stale \"already loaded\" state.\n        console.warn('[chat-session] loadSession failed for', sessionId, errorMessageFrom(err))\n        return false\n      }\n    })()\n\n    loadingSessions.set(sessionId, loadPromise)\n    try {\n      return await loadPromise\n    }\n    finally {\n      // Always drain the loading map so a transient failure does not leave\n      // a permanent wedge entry.\n      loadingSessions.delete(sessionId)\n    }\n  }\n\n  /** Forces the next session load to merge the latest IndexedDB record into memory. */\n  async function refreshSession(sessionId: string): Promise<boolean> {\n    staleSessions.add(sessionId)","sourceCodeStart":417,"sourceCodeEnd":453,"githubUrl":"https://github.com/moeru-ai/airi/blob/f679616c34f1cf6d282c8d64264242af944b3fed/packages/stage-ui/src/stores/chat/session-store.ts#L417-L453","documentation":"loadSession wraps the whole load path — reading the canonical conversation from IDB, optional cloud pull via pullCloudMessages, and ensureSession — in a try/catch. On failure it logs the sessionId plus the error and returns false; crucially it does NOT mark the session as loaded, so the next loadSession call retries rather than fast-returning on stale state, and the loadingSessions map entry is always drained in finally.","triggerScenarios":"The IDB read transaction aborts (version change, connection closed), stored data fails to deserialize into the expected conversation shape, or the cloud-sync pull throws (auth failure, network, unexpected response) when a cloud backend is configured.","commonSituations":"Browser evicted/cleared IDB data while the app cached an in-memory session list; app version upgrade changing the stored schema without migration; sync token/session expired causing pullCloudMessages to reject; corrupted record for one session after a crash mid-write.","solutions":["Read the logged cause: IDB errors (NotFoundError/DataError) point to missing/renamed object stores — clear stale DB or add a schema migration.","For cloud pull failures, re-authenticate the sync backend and retry loading the session (retry is automatic on next call).","Add defensive deserialization so one corrupted record cannot fail the whole session load.","If storage was evicted, accept the loss path: ensureSession will rebuild an empty canonical conversation on the next successful load."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"function sessionExistsInIdb(sessionId: string): Promise<boolean> {\n  // lightweight existence probe before full load, if the IDB wrapper exposes it\n  return idbStore.has(sessionId)\n}","typeGuard":"function isCloudSyncError(err: unknown): boolean {\n  const msg = errorMessageFrom(err)\n  return msg.includes('401') || msg.includes('403') || msg.includes('fetch failed')\n}","tryCatchPattern":"try {\n  return await loadSessionInternal(sessionId)\n}\ncatch (err) {\n  // do not mark loaded; next call retries (existing contract)\n  if (isCloudSyncError(err)) {\n    // prompt re-auth for the sync backend, then call loadSession again\n  }\n  console.warn('[chat-session] loadSession failed for', sessionId, errorMessageFrom(err))\n  return false\n}","preventionTips":["Add schema migration/versioning for stored conversations to survive app upgrades.","Re-auth cloud sync tokens proactively before they expire.","Defensively validate deserialized records so one bad session cannot fail the load path repeatedly."],"tags":["indexeddb","session-loading","cloud-sync","chat-session"],"backgroundTag":"indexeddb-read-failed","analyzedSha":"f679616c34f1cf6d282c8d64264242af944b3fed","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}