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

  1. Check the response body of the failed POST for a detail message — it usually names the missing/invalid field.
  2. Confirm sessionId is a live session (GET the session or create one first).
  3. If 422, diff the backend's DocumentCreate schema against the sent body {session_id, title, content, language}.
  4. 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

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


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/a51840a72326c992. Report an issue: GitHub.