odysseus-dev/odysseus · error · HTTPException

Failed to create document: {e}

Error message

Failed to create document: {e}

What it means

Generic 500 raised by POST /api/documents when any unexpected exception escapes the create-document flow (the except Exception wrapper after db.rollback()). The original exception is interpolated into the message, so the text after the colon is the real cause (usually a SQLAlchemy IntegrityError, a missing column, or a serialization failure in _doc_to_dict). HTTPException subclasses are re-raised untouched; everything else becomes a 500.

Source

Thrown at routes/document/document_routes.py:216

                summary="Initial version",
                source="user",
            )
            db.add(doc)
            db.add(ver)
            db.commit()
            db.refresh(doc)
            try:
                from src.event_bus import fire_event
                fire_event("document_created", doc.owner)
            except Exception:
                logger.debug("document_created event dispatch failed", exc_info=True)
            return _doc_to_dict(doc)
        except HTTPException:
            raise
        except Exception as e:
            db.rollback()
            logger.error(f"Failed to create document: {e}")
            raise HTTPException(500, f"Failed to create document: {e}")
        finally:
            db.close()

    # ---- POST /api/documents/import-pdf ----
    @router.post("/api/documents/import-pdf")
    async def import_pdf(
        request: Request,
        file: UploadFile = File(...),
        session_id: Optional[str] = Form(None),
    ) -> Dict[str, Any]:
        """Upload a PDF and create the matching Document.

        Detects AcroForm fields — if any, creates a form-backed markdown doc
        (clickable inputs in the PDF view). Otherwise creates a plain PDF doc
        with a `pdf_source` marker so the viewer renders the pages without
        overlays.
        """
        from src.pdf_forms import has_form_fields, extract_fields

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Read the server log line 'Failed to create document: <e>' — the interpolated exception is the actual root cause.
  2. If it is an OperationalError/NoSuchColumnError, run the project's DB migration or recreate the dev database so the schema matches the Document model.
  3. If it is an IntegrityError, inspect the request body for missing required fields (owner/session linkage) and fix the client payload.
  4. Reproduce locally with the same payload and --log-level debug to get the full traceback.

Example fix

// before
curl -X POST /api/documents -d '{"title":"x"}' # 500 Failed to create document: NOT NULL constraint failed
// after
# migrate the DB, then send a payload with all required fields
curl -X POST /api/documents -d '{"title":"x","language":"markdown","content":"..."}'
Defensive patterns

Strategy: try-catch

Try / catch

try {
  const doc = await api.post('/api/documents', payload);
} catch (e) {
  if (e.status === 500 && /Failed to create document/.test(e.message)) {
    // surface server detail; the suffix after the colon is the root cause
    notify('Create failed: ' + e.message.split(': ').slice(1).join(': '));
  } else throw e;
}

Prevention

When it happens

Trigger: POST /api/documents with a payload that violates a DB constraint (duplicate id, NOT NULL owner), a schema drift between the Document model and the actual table (column added in code but not migrated), or an exception thrown by db.commit()/db.refresh() inside the try block.

Common situations: Running the API against an older SQLite/Postgres database that was never migrated after model changes; concurrent creates hitting a unique constraint; an event-bus or session-id bug surfacing before the HTTPException re-raise guard.

Related errors


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