{"record":{"id":"ff950d3300fa67a4","repo":"odysseus-dev/odysseus","slug":"documents-integration-is-not-available","errorCode":null,"errorMessage":"Documents integration is not available","messagePattern":"Documents integration is not available","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"error","filePath":"routes/codex_routes.py","lineNumber":345,"sourceCode":"            lines.append(f\"Cc: {cc}\")\n        if bcc:\n            lines.append(f\"Bcc: {bcc}\")\n        lines.append(f\"Subject: {subject}\")\n        if in_reply_to:\n            lines.append(f\"In-Reply-To: {in_reply_to}\")\n        if references:\n            lines.append(f\"References: {references}\")\n        lines.extend([\"---\", body_text])\n        return \"\\n\".join(lines).rstrip() + \"\\n\"\n\n    @router.post(\"/emails/draft-document\")\n    async def codex_email_draft_document(request: Request, body: dict[str, Any] = Body(default_factory=dict)):\n        owner = _scope_owner(request, EMAIL_DRAFT_SCOPES)\n        docs_owner = _scope_owner_all(request, DOCS_WRITE_SCOPES)\n        if docs_owner != owner:\n            raise HTTPException(403, \"API token owner mismatch\")\n        if documents_create_endpoint is None:\n            raise HTTPException(503, \"Documents integration is not available\")\n        from routes.document_routes import DocumentCreate\n\n        subject = str(body.get(\"subject\") or \"Email draft\").strip() or \"Email draft\"\n        title = str(body.get(\"title\") or subject).strip() or \"Email draft\"\n        req = DocumentCreate(\n            session_id=body.get(\"session_id\"),\n            title=title,\n            language=\"email\",\n            content=_email_draft_document_content(body),\n        )\n        result = await _as_owner(request, owner, documents_create_endpoint, request, req)\n        if isinstance(result, dict):\n            result = dict(result)\n            result[\"draft_type\"] = \"document\"\n            result[\"send_required_confirmation\"] = True\n        return result\n\n    @router.post(\"/emails/draft\")","sourceCodeStart":327,"sourceCodeEnd":363,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/codex_routes.py#L327-L363","documentation":"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.","triggerScenarios":"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.","commonSituations":"Documents feature disabled in deployment; version skew after a document-routes refactor renamed the create endpoint; custom app assembly omitting the document router.","solutions":["Confirm POST on the documents create route works directly; if not, enable/mount the document integration.","Ensure setup_codex_routes receives a built document_router at startup.","Align app version so codex_routes matches document_routes' current paths.","If documents are intentionally disabled, use POST /api/codex/emails/draft instead (email-only draft)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const docsOk = await fetch('/api/documents', {method: 'OPTIONS'}).then(r => r.status !== 404);\nif (!docsOk) useEmailOnlyDraft();","typeGuard":null,"tryCatchPattern":"try { r = await codexEmailDraftDocument(body) } catch (e) { if (e.status === 503) { return codexEmailDraft(body) /* email-only fallback */ } throw }","preventionTips":["Feature-detect the documents integration before offering draft-document actions.","Keep a code path to the email-only draft endpoint as graceful degradation.","Assert documents_create_endpoint resolves during app startup tests."],"tags":["http-503","integration","documents","codex","wiring"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}