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_fieldsView on GitHub (pinned to f9235ebbf1)
Solutions
- Read the server log line 'Failed to create document: <e>' — the interpolated exception is the actual root cause.
- If it is an OperationalError/NoSuchColumnError, run the project's DB migration or recreate the dev database so the schema matches the Document model.
- If it is an IntegrityError, inspect the request body for missing required fields (owner/session linkage) and fix the client payload.
- 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
- Validate required fields client-side before POST
- Keep DB schema migrated before deploying new models
- Never retry a 500 create blindly — the row may have partially committed
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
- Failed to delete calendar
- Failed to list calendars
- Failed to create calendar
- Failed to update calendar
- Failed to fetch document library: {e}
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/a5a183576d5426c1.
Report an issue: GitHub.