odysseus-dev/odysseus · error · Error
detail || `HTTP ${res.status}`
Error message
detail || `HTTP ${res.status}` What it means
Thrown by _chatAboutResearch in research/panel.js when POST /api/research/spinoff/{researchId} fails. The client attempts to extract a FastAPI-style detail from the JSON body; if absent or unparseable it falls back to the bare HTTP status. The catch re-enables the button and alerts, so UI state is restored.
Source
Thrown at static/js/research/panel.js:1226
setTimeout(() => { btn.innerHTML = orig; }, 2000);
}
}
}
// ── Chat about this research (server-side spinoff) ──
async function _chatAboutResearch(researchId, btn) {
if (!researchId) return;
const origLabel = btn ? btn.innerHTML : '';
if (btn) { btn.disabled = true; btn.innerHTML = `${_chatIcon} Creating…`; }
try {
const res = await fetch(`${_apiBase}/api/research/spinoff/${researchId}`, {
method: 'POST', credentials: 'same-origin',
});
if (!res.ok) {
let detail = '';
try { detail = (await res.json()).detail || ''; } catch {}
throw new Error(detail || `HTTP ${res.status}`);
}
const payload = await res.json();
if (_sessionModule && _sessionModule.selectSession && payload.session_id) {
if (_sessionModule.loadSessions) await _sessionModule.loadSessions().catch(() => {});
await _sessionModule.selectSession(payload.session_id);
closePanel();
} else if (payload.session_id) {
window.location.hash = '#' + payload.session_id;
window.location.reload();
} else {
// 200 OK but no session_id — server contract violation. Don't leave
// the button stuck on 'Creating…'; surface the failure instead.
throw new Error('Server returned no session id');
}
} catch (e) {
if (btn) { btn.disabled = false; btn.innerHTML = origLabel; }
alert('Could not start follow-up chat: ' + e.message);
}View on GitHub (pinned to f9235ebbf1)
Solutions
- Close and reopen the research panel to refresh ids, then retry.
- Read the detail in the alert for the server's reason; check server logs for 5xx.
- Re-authenticate if the status is 401.
- Verify the research entry still exists in the panel list.
Defensive patterns
Strategy: try-catch
Validate before calling
if (!researchId) { btn.disabled = false; return; } Type guard
const isSpinoffPayload = (p) => !!p && !!p.session_id;
Try / catch
try { ... } catch (e) { btn.disabled = false; btn.innerHTML = origLabel; alert('Could not start follow-up chat: ' + e.message); } Prevention
- Restore button state in a finally-style catch as this code does
- Extract detail from JSON before falling back to status
- Refresh research ids when the panel regains focus
When it happens
Trigger: Creating a follow-up chat from a research report whose id no longer exists (404); research data deleted between panel open and click; server cannot create the spinoff session (db error → 500 with detail); auth expired (401 with empty body → 'HTTP 401').
Common situations: Stale research panel left open while the server restarted or the research store was cleared; long-lived tabs with expired sessions.
Related errors
- await res.text()
- Server returned no session id
- HTTP ' + r.status
- detail || ('HTTP ' + res.status)
- errData.detail || 'Failed to create session'
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/989ec95552bd6a05.
Report an issue: GitHub.