odysseus-dev/odysseus · warning · Error
Failed to archive session
Error message
Failed to archive session
What it means
Thrown by the archive action in sessions.js when POST /api/session/{id}/archive returns non-ok. The status and body are discarded entirely — the same fixed string is used both for the throw and the catch's showError, so 'Failed to archive session' carries no diagnostic information. The dropdown is simply left open.
Solutions
- Reload the session list (loadSessions) and retry on the current id.
- If cross-origin, add credentials:'same-origin' to the fetch (see exampleFix).
- Check server logs for the real status behind the generic message.
- Include the status in the error text for future diagnosability.
Example fix
// before
const response = await fetch(`${API_BASE}/api/session/${s.id}/archive`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
if (!response.ok) { throw new Error('Failed to archive session'); }
// after
const response = await fetch(`${API_BASE}/api/session/${s.id}/archive`, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' }
});
if (!response.ok) { throw new Error(`Failed to archive session (HTTP ${response.status})`); } Defensive patterns
Strategy: try-catch
Try / catch
try { if (!response.ok) throw new Error(`Failed to archive session (HTTP ${response.status})`); await loadSessions(); } catch (error) { uiModule.showError('Failed to archive session'); dropdown.style.display = 'none'; } Prevention
- Send credentials:'same-origin' on every API fetch for cookie consistency
- Include the status code in the message
- Hide the dropdown in the error path too so UI state stays consistent
When it happens
Trigger: Archiving a session id the server no longer has (404, deleted elsewhere); session store write failure (500); missing credentials header handling — note this fetch sends Content-Type but not credentials:'same-origin', so a strict cookie policy can yield 401/302.
Common situations: Stale session list after another device deleted the conversation; cross-origin deployment where same-origin credentials are required but not sent; backend storage locked.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/418eaabb5a8e332c.
Report an issue: GitHub.
Appendix: source
Thrown at static/js/sessions.js:926
} catch (e) { /* network error — session may still exist server-side */ }
await loadSessions();
});
archiveItem.addEventListener('click', async () => {
dropdown.style.display = 'none';
_forceSidebarOpen();
try {
const response = await fetch(`${API_BASE}/api/session/${s.id}/archive`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) {
_forceSidebarOpen();
await loadSessions();
dropdown.style.display = 'none';
uiModule.showToast('Session archived');
} else {
throw new Error('Failed to archive session');
}
} catch (error) {
console.error('Error archiving session:', error);
uiModule.showError('Failed to archive session');
}
});
// Dropdowns are closed by the shared global listener (_initDropdownDismiss)
// Prevent dropdown from closing when clicking inside it
dropdown.addEventListener('click', (e) => {
e.stopPropagation();
});
div.appendChild(span);
// Apply processing/completed state to the star dot
var _isProcessing = _researchingSessions.has(s.id) || _streamingSessions.has(s.id);View on GitHub (pinned to f9235ebbf1)