odysseus-dev/odysseus · error · HTTPException

Document has no source email — cannot reply

Error message

Document has no source email — cannot reply

What it means

Error "Document has no source email — cannot reply" thrown in odysseus-dev/odysseus.

Source

Thrown at routes/document/document_routes.py:1651

        from src.pdf_forms import fill_fields, stamp_signatures, stamp_annotations
        from core.database import Signature
        # COMPOSE_UPLOADS_DIR lives in email_routes — re-derive here so we
        # don't import from a routes file (cycle-prone). Same env override
        # as email_routes (ODYSSEUS_MAIL_ATTACHMENTS_DIR).
        from pathlib import Path as _Path
        _COMPOSE_DIR = _Path(MAIL_ATTACHMENTS_DIR) / "_compose"
        _COMPOSE_DIR.mkdir(parents=True, exist_ok=True)

        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)

            if not (doc.source_email_uid and doc.source_email_folder):
                raise HTTPException(400, "Document has no source email — cannot reply")

            # 1) Build the flattened PDF (same pipeline as export_pdf)
            upload_id = find_source_upload_id(doc.current_content or "")
            if not upload_id:
                raise HTTPException(400, "Document is not linked to a source PDF")
            pdf_path = _locate_current_user_upload(request, upload_id, user)
            if not pdf_path:
                raise HTTPException(404, f"Source PDF {upload_id} not found")

            schema = load_field_sidecar(pdf_path) or []
            sig_field_names = {f["name"] for f in schema if f.get("type") == "signature"}
            all_values = parse_markdown_to_values(doc.current_content or "")
            text_values: dict = {}
            sig_ids: dict[str, str] = {}
            for name, raw in all_values.items():
                if name in sig_field_names and isinstance(raw, str) and raw.startswith("signature:"):
                    sig_ids[name] = raw[len("signature:"):].strip()
                elif name not in sig_field_names:

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Only use reply on documents created from an email source.
  2. Open the original email and reply from there instead.

When it happens

Trigger: Triggered when the corresponding server-side validation or runtime check at the recorded location rejects the request or operation and returns this error message to the caller.

Common situations: See trigger scenarios.


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