Skip to content

fix(api): handle organizations with no emissions in /sums (#693)#1172

Merged
inimaz merged 1 commit into
mlco2:masterfrom
Hore01:fix/organization-empty-sums-693
May 7, 2026
Merged

fix(api): handle organizations with no emissions in /sums (#693)#1172
inimaz merged 1 commit into
mlco2:masterfrom
Hore01:fix/organization-empty-sums-693

Conversation

@Hore01
Copy link
Copy Markdown
Contributor

@Hore01 Hore01 commented May 6, 2026

Description

GET /organizations/{organization_id}/sums returns {"detail": "Generic error"} with status 500 for any organization that has no emissions logged in the requested period. The expected response, per the issue, is a report whose numeric fields are zero.

The fix lives in OrganizationSumsUsecase.compute_detailed_sum. When the repository returns None (which happens because the timestamp filter on Emission cancels the outer joins for an empty organization), the usecase now uses the existing get_one_organization helper to fetch the organization metadata and returns a zero-valued OrganizationReport.

I left the SQL in get_organization_detailed_sums untouched. Rewriting the joins would be a larger, more invasive change; handling the empty result in the usecase keeps the patch focused on what the issue asks for.

Related Issue

Closes #693.

Motivation and Context

Anyone who creates an organization and inspects the sums endpoint before logging any emissions hits a 500. From the outside it looks like the API is broken. Returning zeros is what the issue describes as the ideal response, and it matches the shape the dashboard expects for a quiet period.

How Has This Been Tested?

I ran the affected suite locally on Python 3.12.4 with the dev extras installed:

pytest tests/api/usecase/organization/test_organization_detailed_sums.py -vv

Both tests pass. To make sure the new test actually catches the bug I temporarily reverted the fix and re-ran it. Without the fix it fails on AttributeError: 'NoneType' object has no attribute 'organization_id', which is exactly the path that ends up in the global exception handler. With the fix back in place it passes.

I also ran the broader unit suite to check for regressions:

pytest tests/api/usecase tests/api/service tests/api/routers -q

86 passed, 1 skipped, 1 xfailed, 4 warnings (all pre-existing and unrelated to this change). I did not run the integration suite because I am not running PostgreSQL locally; CI will exercise it.

Screenshots (if appropriate):

n/a — server-side bug fix, no UI change.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

AI Usage Disclosure

  • 🟥 AI-vibecoded
  • 🟠 AI-generated
  • ⭐ AI-assisted
  • ♻️ No AI used

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the docs/how-to/contributing.md document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

GET /organizations/{id}/sums returns 500 with `{"detail": "Generic error"}`
for any organization that has no emissions logged in the requested
period. From the dashboard side this makes new or quiet organizations
look broken.

Tracing through `get_organization_detailed_sums`, the joins are outer
joins but the timestamp filter on `Emission` ends up in the WHERE clause
and so cancels them out for empty organizations. The query returns
nothing, `.first()` returns `None`, and the router hands `None` back to
FastAPI which trips the global exception handler and masks the real
shape of the response.

I kept the SQL alone and handled the empty case in the usecase, where
`get_one_organization` is already available for the metadata. When the
sums query comes back as `None` we look the organization up and return
a zero-valued `OrganizationReport`. Rebuilding the joins would be a
larger, more invasive change than what the issue asks for.

Added a parallel unit test in
`tests/api/usecase/organization/test_organization_detailed_sums.py`
that mocks both repository methods so it runs without a database. On
the unfixed code it fails on the first attribute access on `None`; on
the fixed code it passes. The existing happy-path test is unchanged.

Closes mlco2#693
@Hore01 Hore01 requested a review from a team as a code owner May 6, 2026 21:54
Copy link
Copy Markdown
Collaborator

@inimaz inimaz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice @Hore01 ! Thanks for this. Merging it

@inimaz inimaz merged commit cf6557a into mlco2:master May 7, 2026
8 checks passed
gregoirevilde-se added a commit to gregoirevilde-se/codecarbon that referenced this pull request May 7, 2026
* fix(api): handle organizations with no emissions in /sums (mlco2#693) (mlco2#1172)

GET /organizations/{id}/sums returns 500 with `{"detail": "Generic error"}`
for any organization that has no emissions logged in the requested
period. From the dashboard side this makes new or quiet organizations
look broken.

Tracing through `get_organization_detailed_sums`, the joins are outer
joins but the timestamp filter on `Emission` ends up in the WHERE clause
and so cancels them out for empty organizations. The query returns
nothing, `.first()` returns `None`, and the router hands `None` back to
FastAPI which trips the global exception handler and masks the real
shape of the response.

I kept the SQL alone and handled the empty case in the usecase, where
`get_one_organization` is already available for the metadata. When the
sums query comes back as `None` we look the organization up and return
a zero-valued `OrganizationReport`. Rebuilding the joins would be a
larger, more invasive change than what the issue asks for.

Added a parallel unit test in
`tests/api/usecase/organization/test_organization_detailed_sums.py`
that mocks both repository methods so it runs without a database. On
the unfixed code it fails on the first attribute access on `None`; on
the fixed code it passes. The existing happy-path test is unchanged.

Closes mlco2#693

* update cbs deployment

---------

Co-authored-by: Olajumoke Akinremi <[email protected]>
@benoit-cty benoit-cty mentioned this pull request May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API] Sums by organization returns error

2 participants