-
Notifications
You must be signed in to change notification settings - Fork 171
team_index route returns 500 due to lazy-loaded relationship in sync template rendering #66
Description
The GET /{team_slug} route (team_index in routers/team.py) crashes with sqlalchemy.exc.MissingGreenlet when rendering the team dashboard.
Root cause
The deployments query eager-loads Deployment.aliases but not Deployment.project:
select(Deployment)
.options(selectinload(Deployment.aliases))
.join(Project)
...
The template (deployment/macros/list.html) then accesses deployment.project.name, deployment.project.slug, and deployment.environment (a @Property that internally reads self.project). These accesses trigger a lazy load of the project relationship during Jinja2's
synchronous template.render() call, which cannot execute an async DB query — hence MissingGreenlet.
This likely went unnoticed because the ORM identity map usually had Project objects cached from earlier queries in the same request. A Docker restart (or any scenario that clears session state) makes the lazy load actually hit the database, surfacing the bug.
Fix
Add selectinload(Deployment.project) to the deployments query in team_index:
select(Deployment)
.options(selectinload(Deployment.aliases), selectinload(Deployment.project))
.join(Project)
...
Note: .join(Project) only uses Project for filtering — it does not populate the relationship on the result objects. selectinload is needed for that.
Affected file: app/routers/team.py, line ~115