moeru-ai/airi · error
[chat-session] persist task failed:
Error message
[chat-session] persist task failed:
What it means
session-store serializes persistence through a promise chain (enqueuePersist). Each task's rejection is logged here and swallowed so the chain survives for later writes. Failures originate in the IndexedDB layer behind the persist tasks: quota exceeded, database closed/version change mid-write, corruption, or an abort during tab shutdown. Because tasks return the original promise to awaiting callers, callers may also observe the rejection; this log is the queue-level record.
Source
Thrown at packages/stage-ui/src/stores/chat/session-store.ts:167
return cloudMapper
}
/**
* Append a write task to the persist queue. Tasks always run sequentially
* regardless of whether prior tasks rejected — but rejections propagate to
* the awaiting caller AND are surfaced via console for debugging. The
* previous `then(task, task)` form silently swallowed prior rejections by
* running the next task as the rejection handler, which masked IDB
* failures from the cloud-sync cursor tracking that depends on them.
*/
function enqueuePersist<T>(task: () => Promise<T>): Promise<T> {
const next = persistQueue.then(task)
// Keep the queue alive after a rejection but log it so silent IDB
// failures (quota, corruption) surface during dev.
persistQueue = next.then(
() => undefined,
(err) => {
console.warn('[chat-session] persist task failed:', errorMessageFrom(err))
},
)
return next
}
function snapshotMessages(messages: ChatHistoryItem[]) {
return cloneDeep(messages)
}
function ensureSessionMessageIds(sessionId: string) {
const current = sessionMessages.value[sessionId] ?? []
let changed = false
const next = current.map((message) => {
if (message.id)
return message
changed = true
return {
...message,View on GitHub (pinned to f679616c34)
Solutions
- Check the logged message for QuotaExceededError — prune or export old chat history, and consider trimming snapshot payloads.
- Handle versionchange/close events in the IDB wrapper so writes are not attempted on a dead connection.
- Ensure message objects are structured-clone-safe (no functions/DOM refs) before persisting.
- If in private/restricted mode, warn users that chat persistence is unavailable.
Defensive patterns
Strategy: try-catch
Validate before calling
function isStructuredCloneSafe(value: unknown): boolean {
try {
structuredClone(value)
return true
}
catch {
return false
}
}
// validate message payloads before enqueueing persist tasks Type guard
function isQuotaError(err: unknown): boolean {
const name = (err as { name?: string })?.name
return name === 'QuotaExceededError' || errorMessageFrom(err).includes('quota')
} Try / catch
function enqueuePersist<T>(task: () => Promise<T>): Promise<T> {
const next = persistQueue.then(task)
persistQueue = next.then(
() => undefined,
(err) => {
if (isQuotaError(err)) {
// prune history / notify user instead of silently retrying forever
}
console.warn('[chat-session] persist task failed:', errorMessageFrom(err))
},
)
return next
} Prevention
- Keep persisted message snapshots lean; strip volatile/DOM references before storing.
- Verify structured-clone safety of new message fields before persisting them.
- Surface quota errors to the UI so users can export/prune history.
When it happens
Trigger: Any IDB write inside a persist task rejects — large chat histories hitting storage quota, IDB version upgrade closing connections, private-mode/restricted storage (ITP evicting or blocking), or structured-clone failure on non-cloneable message payloads.
Common situations: Long-lived chats accumulating megabytes of history in Safari/WebKit quota; browser data-clearing while the app is open; Firefox private browsing where IDB writes fail; storing non-cloneable values (functions, DOM nodes) accidentally attached to messages.
Related errors
- [chat-session] loadSession failed for
- Gemini TTS request failed: ${response.status} ${await respon
- [mmd] motion file "${descriptor.name}" (${descriptor.id}) no
- web search failed: tavily ${response.status}${detail ? `: ${
- Failed to load the target chat session
AI-assisted analysis of moeru-ai/airi@f679616c34 (2026-08-18).
Data as JSON: /api/errors/ca732e9db2ab2b2f.
Report an issue: GitHub.