odysseus-dev/odysseus · error · Error
Document create failed: HTTP ${res.status}
Error message
Document create failed: HTTP ${res.status} What it means
Thrown in static/js/document.js when POST /api/document (creating a new empty markdown doc, e.g. from the empty-editor bootstrap path) returns non-2xx. The template literal `Document create failed: HTTP ${res.status}` records only the status; the response body (which FastAPI-style backends use for detail) is discarded.
Source
Thrown at static/js/document.js:7044
if (_creatingDoc) return;
_creatingDoc = true;
// If the panel was in empty-state, the user may type into the editor
// during the create round-trip — preserve that text into the new doc
// instead of letting switchToDoc blank it.
const wasEmpty = !activeDocId;
try {
const res = await fetch(`${API_BASE}/api/document`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'same-origin',
body: JSON.stringify({
session_id: sessionId,
title: '',
content: '',
language: 'markdown',
}),
});
if (!res.ok) throw new Error(`Document create failed: HTTP ${res.status}`);
const doc = await res.json();
if (!doc || !doc.id) throw new Error('Document create failed: missing id');
addDocToTabs(doc, sessionId);
if (!isOpen) openPanel();
// Re-enable editor if it was in empty state
let textarea = document.getElementById('doc-editor-textarea');
if (textarea) {
textarea.disabled = false;
textarea.placeholder = 'Document content...';
}
// Capture text typed during the round-trip (only when starting from the
// empty editor — don't steal another doc's content).
const typed = (wasEmpty && textarea && textarea.value.trim()) ? textarea.value : '';
switchToDoc(doc.id);
if (typed) {
textarea = document.getElementById('doc-editor-textarea');
if (textarea) textarea.value = typed;
const d = docs.get(doc.id);View on GitHub (pinned to f9235ebbf1)
Solutions
- Check the response body of the failed POST for a detail message — it usually names the missing/invalid field.
- Confirm sessionId is a live session (GET the session or create one first).
- If 422, diff the backend's DocumentCreate schema against the sent body {session_id, title, content, language}.
- Include the body in the thrown message for future diagnosability.
Example fix
// before
if (!res.ok) throw new Error(`Document create failed: HTTP ${res.status}`);
// after
if (!res.ok) {
let detail = '';
try { const j = await res.json(); detail = j?.detail || j?.error || ''; } catch (_) {}
throw new Error(`Document create failed: HTTP ${res.status}${detail ? ` — ${detail}` : ''}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
const sessionId = sessionModule?.getCurrentSessionId?.() || _lastSessionId;
if (!sessionId) { /* create/await a session first */ } Type guard
function isCreatedDoc(doc) {
return doc != null && typeof doc === 'object' && (typeof doc.id === 'string' || typeof doc.id === 'number');
} Try / catch
try {
const res = await fetch(`${API_BASE}/api/document`, { /* ... */ });
let body = null;
try { body = await res.json(); } catch (_) {}
if (!res.ok) throw new Error(`Document create failed: HTTP ${res.status}${body?.detail ? ' — ' + body.detail : ''}`);
if (!isCreatedDoc(body)) throw new Error('Document create failed: missing id');
} catch (e) {
if (uiModule) uiModule.showError(`Could not create document: ${e.message}`);
} Prevention
- Ensure a valid session exists before the empty-editor bootstrap triggers a create.
- Include the parsed detail in the message so 422s self-explain.
- Keep a typed schema for POST /api/document's response and validate it in one place.
When it happens
Trigger: Typing into a fresh, empty editor which triggers creation with session_id; backend rejects because session_id is invalid/unknown (400/422), auth expired (401), or a server error (500) while inserting the row.
Common situations: Session id from a stale _lastSessionId after server restart wiped sessions; database locked or migration pending; deploy where POST /api/document gained required fields the frontend doesn't send.
Related errors
- data?.error || data?.detail || `HTTP ${res.status}`
- (data && (data.error || data.detail)) || `HTTP ${res.status}
- Document save failed: HTTP ${res.status}
- Import failed
- HTTP ${res.status}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/a51840a72326c992.
Report an issue: GitHub.