Nobody has started this yet — be first.
Business impact
This API's whole contract for "async work after the response" (see the project README) depends on clients being able to tell the difference between "not ready yet, come back shortly" and "this will never be ready, stop polling." Today those two signals are swapped: a client uploading a perfectly healthy image that just hasn't finished processing gets told 409 IMAGE_PROCESSING_FAILED (a terminal, permanent-looking error) while a client whose image genuinely, permanently failed to process gets told 425 Too Early -- an explicit invitation to keep retrying a request that will never succeed. Any well-behaved client or SDK built against the documented codes (425 = "poll again", 409 = "give up, show the error") will now do exactly the wrong thing in both directions: it will either give up early on images that were about to succeed, or burn retries forever against images that failed for good. That's wasted client-side compute and, for a paying integration, wasted API quota on a service that told them to keep trying.
Problem
GET /images/{id}/thumbnail?size=... checks record.status before allowing a thumbnail download. The branch that should apply when status == PROCESSING now returns the response documented for FAILED (409 IMAGE_PROCESSING_FAILED), and the branch that should apply when status == FAILED now returns the response documented for PROCESSING (425 IMAGE_NOT_READY).
Current behavior
Requesting a thumbnail for a still-processing image returns 409 IMAGE_PROCESSING_FAILED, and requesting one for a genuinely failed image returns 425 IMAGE_NOT_READY -- exactly backwards from what each status code is supposed to mean.
Expected behavior
status == "processing" should return 425 Too Early, error code IMAGE_NOT_READY, with a message inviting a retry. status == "failed" should return 409 Conflict, error code IMAGE_PROCESSING_FAILED, carrying record.error_reason. This is exactly what the project's own README endpoint table and tests/test_processing.py already document -- this ticket is about restoring that contract, not inventing a new one.
Steps to reproduce
cd fastapi/image_service && source .venv/bin/activate pytest -q tests/test_processing.py -v
Why this matters
ImageStatus (app/models.py) has exactly three states -- PROCESSING, READY, FAILED -- and the whole point of exposing status on GET /images/{id} is so a client can build correct polling logic around it. download_thumbnail's two if branches are the only place that translates those states into HTTP semantics for the download endpoint; get either one wrong and the meaning of the status code a client observes is inverted, even though every other part of the app (the metadata endpoint, the background pipeline) still reports the correct underlying status string.
Suggested approach
Read download_thumbnail in app/main.py top to bottom, matching each if record.status == models.ImageStatus.X: branch against the docstring/README description of what that status is supposed to mean, and against tests/test_processing.py's two relevant tests (they assert the intended mapping directly). The fix is entirely within those two if blocks -- no other file needs to change.
Acceptance criteria
Verification
pytest practicetickets/test_ticket04_thumbnail_status_codes.py -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b fix/thumbnail-status-codesFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/thumbnail-status-codesSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign indocker-compose.yml./app./testsuvicorn --reload/app/dataDockerfile.proddocker compose -f docker-compose.prod.yml up --build -dWithout Docker:
cd fastapi/image_service
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
cp .env.example .env # optional, defaults work out of the box
uvicorn app.main:app --reload # -> http://127.0.0.1:8000/docs
Work the tickets in practicetickets/ (TICKET_01 through TICKET_07); each names one dedicated pytest file:
pytest practicetickets/test_ticket01_upload_size_boundary.py -v # a single ticket
./practicetickets/run_tickets.sh # all 7, clean pass/fail summary
Run run_tickets.sh from anywhere -- it cds to the project root itself before running, since app/main.py resolves its SQLite file and upload directory relative to the working directory at import time. pytest -q tests/ (the project's own pre-existing suite, separate from practicetickets/) is also worth running before and after each fix -- three of the four bugs (tickets 02, 04, 06) also break specific pre-existing tests there, and fixing the ticket correctly should make those green again too, with zero changes needed inside tests/ itself.
Level 1
Fix a bug
Read existing behaviour, correct it.