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

  1. Read the actual status from the network tab (the thrown Error carries it)
  2. Verify the sort/search values are among the API's accepted values
  3. Re-login if 401; restart/health-check the backend if connection refused
  4. 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

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.