fix(api): handle organizations with no emissions in /sums (#693)#1172
Merged
Conversation
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
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]>
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
GET /organizations/{organization_id}/sumsreturns{"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 returnsNone(which happens because the timestamp filter onEmissioncancels the outer joins for an empty organization), the usecase now uses the existingget_one_organizationhelper to fetch the organization metadata and returns a zero-valuedOrganizationReport.I left the SQL in
get_organization_detailed_sumsuntouched. 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:
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:
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
AI Usage Disclosure
Checklist: