Skip to content

team_index route returns 500 due to lazy-loaded relationship in sync template rendering #66

@oransom

Description

@oransom

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions