Percentile Calculator returns 500 for stations that have no pre-calculated data file
- Dominant language
- Python
- Stars
- 65
- Forks
- 11
- Avg merge
- 21h 25m
- Merged PRs (30d)
- 70
Description
## Summary
`POST /api/percentiles/` returns a 500 when a requested station has no pre-calculated data file. Because codes are processed as a batch, one such station also fails every other station selected alongside it.
## Steps to reproduce
Breaks (VANCOUVER AP, code 69):
https://psu.nrs.gov.bc.ca/percentile-calculator?codes=69&timeRange=10
Works (codes 213 and 267):
https://psu.nrs.gov.bc.ca/percentile-calculator?codes=213,267&timeRange=10
Adding the unsupported station breaks the working pair:
https://psu.nrs.gov.bc.ca/percentile-calculator?codes=213,267,69&timeRange=10
Selecting only stations that have data works:

Adding VANCOUVER AP (EC) (69) to that same pair fails the whole request:

Against production:
```
POST /api/percentiles/ {"stations":[213], ...} -> 200
POST /api/percentiles/ {"stations":[267], ...} -> 200
POST /api/percentiles/ {"stations":[213,267], ...} -> 200
POST /api/percentiles/ {"stations":[1142], ...} -> 500
POST /api/percentiles/ {"stations":[1142,213,267], ...} -> 500
```
The page shows "Error occurred (while getting the calculation result)."
## Cause
`app/percentile.py` builds a filename per station code and calls `StationSummary.parse_file(filename)` with no existence check, so a missing file raises `FileNotFoundError` and surfaces as a 500.
The same function already returns a clean 400 for its other two failure modes (empty station list, unsupported year range). A missing data file looks like the case that was not covered.
## Expected
A 400 naming the unsupported codes, consistent with the existing 400s, and without failing the other stations in the request.
There is precedent that a data-less station is not meant to error: ten currently-selectable stations have null pre-calculated values and return 200, rendering as "Not available" with a "Data only available for 0 of 10 years" notice, e.g.
https://psu.nrs.gov.bc.ca/percentile-calculator?codes=321&timeRange=10

The only difference between that and a 500 is whether a file exists on disk:
```
321 (file present, values null) -> 200, "Not available"
1142 (no file) -> 500
```
Am I missing something here? If the 500 is expected for some reason I haven't spotted, happy to be corrected.
PR to follow.
Contributor guide
Research direction
Start by reproducing the request against POST /api/percentiles/ and read app/percentile.py, especially the existing 400 responses and the StationSummary.parse_file(filename) call. Done means a missing-data station produces a 400 naming the unsupported code while valid stations in the same batch still succeed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100