odysseus-dev/odysseus · error · Error
Session request returned an invalid response
Error message
Session request returned an invalid response
What it means
Thrown by loadSessions in sessions.js when the sessions request succeeded (or was cached) but res.json() did not yield an array. It is distinct from the HTTP-status error just above it ('Session request failed (HTTP n)'), which carries .status — this one means the payload shape is wrong despite a 2xx.
Source
Thrown at static/js/sessions.js:1699
let url = `${API_BASE}/api/sessions`;
if (currentSessionId && _isIncognitoSession(currentSessionId)) {
url += `?active_incognito_id=${encodeURIComponent(currentSessionId)}`;
}
const res = await fetch(url);
if (!res.ok) {
let detail = '';
try {
const payload = await res.json();
detail = payload?.detail || payload?.error || '';
} catch (_) {}
const error = new Error(detail || `Session request failed (HTTP ${res.status})`);
error.status = res.status;
throw error;
}
fetched = await res.json();
}
if (!Array.isArray(fetched)) {
throw new Error('Session request returned an invalid response');
}
sessions = _normalizeSessionsList(fetched);
renderSessionList();
const sessionsSection = uiModule.el('sessions-section');
if (sessions.length === 0) {
sessionsSection.classList.add('hidden');
} else {
sessionsSection.classList.remove('hidden');
}
const activeSessions = sessions.filter(s => !s.archived);
// "Transient" sessions = the singleton Assistant chat + any task-output
// session. Treat them as not-restorable so coming back to the app lands
// on the user's last actual conversation, not whichever check-in task
// most recently appended a message.
const _isTransient = (s) => !!s && (s.folder === 'Assistant' || s.folder === 'Tasks');
const _realSessions = activeSessions.filter(s => !_isTransient(s));View on GitHub (pinned to f9235ebbf1)
Solutions
- Inspect the network response for /api/session* — compare its top-level shape with Array.isArray expectation.
- If wrapped, unwrap in the client (see exampleFix) or revert the server to a bare array.
- Fix proxy/SPA fallback config so API routes are not served index.html.
- Ensure auth redirects return JSON errors, not HTML.
Example fix
// before
fetched = await res.json();
if (!Array.isArray(fetched)) { throw new Error('Session request returned an invalid response'); }
// after (accept wrapped envelope)
fetched = await res.json();
const list = Array.isArray(fetched) ? fetched : fetched?.sessions ?? fetched?.items;
if (!Array.isArray(list)) { throw new Error('Session request returned an invalid response'); }
sessions = _normalizeSessionsList(list); Defensive patterns
Strategy: type-guard
Type guard
const isSessionList = (v) => Array.isArray(v) || Array.isArray(v?.sessions) || Array.isArray(v?.items);
Try / catch
try { fetched = await res.json(); const list = Array.isArray(fetched) ? fetched : fetched?.sessions ?? fetched?.items; if (!Array.isArray(list)) throw new Error('Session request returned an invalid response'); } catch (e) { showError(e.message); renderSessionList(); /* render cached/empty rather than blank */ } Prevention
- Keep the sessions endpoint returning a bare array, or version the envelope when changing it
- Configure proxies so /api/* is never served the SPA index.html
- Type-check the parsed shape before mutating global session state
When it happens
Trigger: The sessions endpoint returning a wrapped object like {sessions:[...]} instead of a bare array; a 200 HTML page from a misrouted proxy or the SPA index fallback; a server version change to a paginated envelope {items, total}; JSON parsing of an empty body producing undefined.
Common situations: Frontend/backend version skew after an API envelope refactor; catch-all SPA routing serving index.html for /api/session on misconfigured hosts; login pages returned in place of JSON when auth middleware redirects.
Related errors
- ${cfg.label} sign-in did not return a poll id
- Server returned no session id
- Tidy failed
- Failed to archive session
- GitHub device-code request failed: {e}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/d6581deb61e1dd49.
Report an issue: GitHub.