odysseus-dev/odysseus · warning · HTTPException

Document not found

Error message

Document not found

What it means

404 from GET /api/document/{doc_id}: no Document row matches the given id before ownership checks run. The id may be malformed, the document may have been soft-deleted by a path that filters it from this query, or it simply never existed.

Source

Thrown at routes/document/document_routes.py:476

            q = db.query(Document).filter(
                Document.session_id == session_id
            )
            if user:
                q = q.filter(or_(Document.owner == user, Document.owner.is_(None)))
            docs = q.order_by(Document.created_at.desc()).all()
            return [_doc_to_dict(d) for d in docs]
        finally:
            db.close()

    # ---- GET /api/document/{doc_id} ----
    @router.get("/api/document/{doc_id}")
    async def get_document(request: Request, doc_id: str) -> Dict[str, Any]:
        user = get_current_user(request)
        db = SessionLocal()
        try:
            doc = db.query(Document).filter(Document.id == doc_id).first()
            if not doc:
                raise HTTPException(404, "Document not found")
            _verify_doc_owner(db, doc, user)
            return _doc_to_dict(doc)
        finally:
            db.close()

    # ---- POST /api/document/{doc_id}/archive — soft-archive / restore ----
    @router.post("/api/document/{doc_id}/archive")
    async def archive_document(request: Request, doc_id: str, archived: bool = Query(True)) -> Dict[str, Any]:
        user = get_current_user(request)
        db = SessionLocal()
        try:
            doc = db.query(Document).filter(Document.id == doc_id).first()
            if not doc:
                raise HTTPException(404, "Document not found")
            _verify_doc_owner(db, doc, user)
            doc.archived = bool(archived)
            db.commit()
            return {"ok": True, "id": doc_id, "archived": doc.archived}

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Verify the doc id against GET /api/documents/library to confirm it still exists for this user.
  2. If it was soft-deleted, restore it through the app's restore path instead of retrying the GET.
  3. Fix the client to clear doc references when a delete/404 is returned rather than re-requesting the dead id.
  4. Check the URL for encoding issues (truncated ids, stray characters).

Example fix

// before
const doc = await api.get(`/api/document/${id}`); // throws on 404
// after
const doc = await api.get(`/api/document/${id}`).catch((e) => {
  if (e.status === 404) { router.push('/library'); return null; }
  throw e;
});
Defensive patterns

Strategy: try-catch

Validate before calling

const exists = (await api.get('/api/documents/library')).documents.some(d => d.id === id);
if (!exists) { router.push('/library'); return; }

Type guard

function isDocId(id: unknown): id is string {
  return typeof id === 'string' && /^[A-Za-z0-9_-]{6,}$/.test(id);
}

Try / catch

try { return await api.get(`/api/document/${id}`); }
catch (e) { if (e.status === 404) { dropDocReference(id); return null; } throw e; }

Prevention

When it happens

Trigger: Client holds a stale doc id from an earlier session (document deleted via DELETE /api/document/{doc_id}); typo'd or truncated UUID in the URL; the doc exists but with an archived flag handled by a different listing route.

Common situations: Browser refresh on a doc editor after the doc was deleted elsewhere; deep links bookmarked to deleted docs; frontend state desync after bulk operations.

Related errors


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