odysseus-dev/odysseus · error · Error
Failed to load research
Error message
Failed to load research
What it means
Inline grid message shown when loading the research library fails. _renderLibResearch fetches /api/research/library with limit/sort/search params and throws new Error(res.status) on any non-OK response; note the error is created but this outer handler renders 'Failed to load research' (the sibling documents grid shows the analogous text).
Source
Thrown at static/js/sessions.js:3458
e.stopPropagation();
_showDropdown(e.currentTarget, [
{ label: 'Open', action: () => { if (d.session_id) { closeLibrary(); selectSession(d.session_id); } } },
{ label: 'Delete', action: async () => { if (!await uiModule.styledConfirm('Delete?', { confirmText: 'Delete', danger: true })) return; await fetch(`${API_BASE}/api/document/${d.id}`, { method: 'DELETE' }); _renderLibGrid(); }, danger: true },
]);
});
grid.appendChild(card);
}
} catch (e) { console.error('Library documents error:', e); grid.innerHTML = '<div class="doclib-empty">Failed to load documents</div>'; }
}
async function _renderLibResearch(grid) {
grid.innerHTML = '';
grid.appendChild(spinnerModule.createLoadingRow('Loading research…'));
try {
const params = new URLSearchParams({ limit: '50', sort: _lib.sort });
if (_lib.search) params.set('search', _lib.search);
const res = await fetch(`${API_BASE}/api/research/library?${params}`);
if (!res.ok) throw new Error(res.status);
const data = await res.json();
const items = data.research || [];
const statsEl = document.getElementById('lib-stats');
if (statsEl) statsEl.textContent = `${data.total || 0} research`;
grid.innerHTML = '';
if (!items.length) {
grid.innerHTML = '<div class="doclib-empty">No research found</div>';
return;
}
for (const item of items) {
const meta = [
item.duration || '',
item.rounds ? item.rounds + ' rounds' : '',
].filter(Boolean).join(' \u00b7 ');
const card = _buildLibCard(
item.id, item.query || '(untitled)', item.source_count || 0,
meta, item.completed_at ? new Date(item.completed_at * 1000).toISOString() : '',
false, false,View on GitHub (pinned to f9235ebbf1)
Solutions
- Read the actual status from the network tab (the thrown Error carries it)
- Verify the sort/search values are among the API's accepted values
- Re-login if 401; restart/health-check the backend if connection refused
- Catch and display e.message (the status) in the empty-state instead of a fixed string
Example fix
// before
} catch (e) {
grid.innerHTML = '<div class="doclib-empty">Failed to load research</div>';
}
// after
} catch (e) {
console.error('library research error:', e);
grid.innerHTML = `<div class="doclib-empty">Failed to load research (${e.message})</div>`;
} Defensive patterns
Strategy: try-catch
Validate before calling
const VALID_SORTS = ['newest','oldest'];
if (!VALID_SORTS.includes(_lib.sort)) _lib.sort = 'newest';
if (!navigator.onLine) { grid.innerHTML = '<div class="doclib-empty">Offline</div>'; return; } Try / catch
try { const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); ... } catch (e) { grid.innerHTML = `<div class="doclib-empty">Failed to load research (${e.message})</div>`; } Prevention
- Whitelist sort/search values against the API contract
- Handle 401 with a re-login prompt instead of an error row
- Show the HTTP status in the empty-state
- Abort in-flight loads when the tab changes to avoid race-rendered errors
When it happens
Trigger: GET /api/research/library?limit=50&sort=...&search=... returns non-2xx — malformed sort param, invalid search encoding, 401 — or the fetch itself rejects (server down, offline).
Common situations: Backend not running or restarted; auth expired while library tab open; an unsupported sort value left in module state; very large search strings breaking the query.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/dfea7a9a5353a5c1.
Report an issue: GitHub.