odysseus-dev/odysseus · error · HTTPException

Documents integration is not available

Error message

Documents integration is not available

What it means

Raised as HTTP 503 by POST /api/codex/emails/draft-document when documents_create_endpoint is None — setup_codex_routes could not resolve the documents-create endpoint on the document router it was given. The route composes email drafting with document creation; without the documents integration mounted it can only report unavailability. Note it fires after the scope and owner checks, so auth was fine.

Solutions

  1. Confirm POST on the documents create route works directly; if not, enable/mount the document integration.
  2. Ensure setup_codex_routes receives a built document_router at startup.
  3. Align app version so codex_routes matches document_routes' current paths.
  4. If documents are intentionally disabled, use POST /api/codex/emails/draft instead (email-only draft).
Defensive patterns

Strategy: try-catch

Validate before calling

const docsOk = await fetch('/api/documents', {method: 'OPTIONS'}).then(r => r.status !== 404);
if (!docsOk) useEmailOnlyDraft();

Try / catch

try { r = await codexEmailDraftDocument(body) } catch (e) { if (e.status === 503) { return codexEmailDraft(body) /* email-only fallback */ } throw }

Prevention

When it happens

Trigger: Calling /emails/draft-document when the document router was not passed to setup_codex_routes or its create route path changed so _find_endpoint returned None.

Common situations: Documents feature disabled in deployment; version skew after a document-routes refactor renamed the create endpoint; custom app assembly omitting the document router.

Related errors


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

Appendix: source

Thrown at routes/codex_routes.py:345

            lines.append(f"Cc: {cc}")
        if bcc:
            lines.append(f"Bcc: {bcc}")
        lines.append(f"Subject: {subject}")
        if in_reply_to:
            lines.append(f"In-Reply-To: {in_reply_to}")
        if references:
            lines.append(f"References: {references}")
        lines.extend(["---", body_text])
        return "\n".join(lines).rstrip() + "\n"

    @router.post("/emails/draft-document")
    async def codex_email_draft_document(request: Request, body: dict[str, Any] = Body(default_factory=dict)):
        owner = _scope_owner(request, EMAIL_DRAFT_SCOPES)
        docs_owner = _scope_owner_all(request, DOCS_WRITE_SCOPES)
        if docs_owner != owner:
            raise HTTPException(403, "API token owner mismatch")
        if documents_create_endpoint is None:
            raise HTTPException(503, "Documents integration is not available")
        from routes.document_routes import DocumentCreate

        subject = str(body.get("subject") or "Email draft").strip() or "Email draft"
        title = str(body.get("title") or subject).strip() or "Email draft"
        req = DocumentCreate(
            session_id=body.get("session_id"),
            title=title,
            language="email",
            content=_email_draft_document_content(body),
        )
        result = await _as_owner(request, owner, documents_create_endpoint, request, req)
        if isinstance(result, dict):
            result = dict(result)
            result["draft_type"] = "document"
            result["send_required_confirmation"] = True
        return result

    @router.post("/emails/draft")

View on GitHub (pinned to f9235ebbf1)