{"record":{"id":"fb113164ce30a978","repo":"odysseus-dev/odysseus","slug":"email-integration-is-not-available","errorCode":null,"errorMessage":"Email integration is not available","messagePattern":"Email integration is not available","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"error","filePath":"routes/codex_routes.py","lineNumber":264,"sourceCode":"        owner = _scope_owner(request, allowed)\n        args = dict(body)\n        args[\"action\"] = action\n        return await do_manage_notes(json.dumps(args), owner=owner)\n\n    @router.get(\"/emails\")\n    async def list_emails(\n        request: Request,\n        folder: str = \"INBOX\",\n        limit: int = 10,\n        offset: int = 0,\n        filter: str = \"all\",\n        from_addr: str | None = None,\n        account_id: str | None = None,\n        has_attachments: int = 0,\n    ):\n        owner = _scope_owner(request, EMAIL_READ_SCOPES)\n        if email_list_endpoint is None:\n            raise HTTPException(503, \"Email integration is not available\")\n        limit = max(1, min(int(limit or 10), 50))\n        offset = max(0, int(offset or 0))\n        if account_id:\n            from routes.email_helpers import _assert_owns_account\n\n            _assert_owns_account(account_id, owner)\n        return await email_list_endpoint(\n            folder=folder,\n            limit=limit,\n            offset=offset,\n            filter=filter,\n            from_addr=from_addr,\n            account_id=account_id,\n            has_attachments=has_attachments,\n            cache_bust=None,\n            owner=owner,\n        )\n","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/codex_routes.py#L246-L282","documentation":"Raised as HTTP 503 by GET /api/codex/emails when email_list_endpoint is None — setup_codex_routes failed to find the endpoint for GET /api/email/list on the email router passed to it. The codex surface is a proxy over the core email integration; if the underlying router was not wired (or its route path/method changed), the proxy reports service-unavailable rather than crashing.","triggerScenarios":"Calling /api/codex/emails when setup_codex_routes was invoked with email_router=None, an empty router, or one whose /api/email/list route was renamed/removed in a newer version.","commonSituations":"Email integration disabled at startup by config; version skew where codex_routes looks up an old email route path; a custom app.py that forgets to pass the email router into setup_codex_routes.","solutions":["Confirm the email integration is enabled and its router is registered — hit GET /api/email/list directly; if that 404s too, the integration is not mounted.","Check the call site of setup_codex_routes to ensure email_router is passed and non-None.","Align versions: upgrade so codex_routes' _find_endpoint path matches the current email router layout.","Re-enable the email feature flag / dependency (e.g. installed mail provider) and restart."],"exampleFix":"# before\napp.include_router(setup_codex_routes(email_router=None, ...))\n\n# after\nfrom routes.email_routes import build_email_router\napp.include_router(setup_codex_routes(email_router=build_email_router(), ...))","handlingStrategy":"validation","validationCode":"async function codexEmailsReady() {\n  const core = await fetch('/api/email/list?limit=1');\n  return core.ok; // if core email API is dead, codex proxy will 503\n}","typeGuard":null,"tryCatchPattern":"try { r = await codexListEmails() } catch (e) { if (e.status === 503) { disableEmailFeatures(); notify('Email integration not available') } else throw }","preventionTips":["Probe the core integration endpoint once at startup and disable dependent UI on failure.","Guarantee setup_codex_routes always receives built routers — assert non-None in tests.","Treat 503 from codex routes as configuration drift, not transient: do not blind-retry."],"tags":["http-503","integration","email","codex","wiring"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}