fix: season-stats update-game returns 404 for nonexistent game_id #117

Merged
cal merged 1 commits from ai/paper-dynasty-database#113 into next-release 2026-03-19 18:18:41 +00:00
Collaborator

Summary

  • Catches DoesNotExist before the generic Exception handler in update_game_season_stats
  • Returns a clean 404 {"detail": "Game {game_id} not found"} instead of leaking raw Peewee SQL in a 500

Closes #113

Test plan

  • POST /api/v2/season-stats/update-game/999999404 {"detail": "Game 999999 not found"}
  • POST /api/v2/season-stats/update-game/{valid_id}200 with updated counts (existing behaviour unchanged)

🤖 Generated with Claude Code

## Summary - Catches `DoesNotExist` before the generic `Exception` handler in `update_game_season_stats` - Returns a clean `404 {"detail": "Game {game_id} not found"}` instead of leaking raw Peewee SQL in a 500 Closes #113 ## Test plan - [ ] `POST /api/v2/season-stats/update-game/999999` → `404 {"detail": "Game 999999 not found"}` - [ ] `POST /api/v2/season-stats/update-game/{valid_id}` → `200` with updated counts (existing behaviour unchanged) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Claude added 1 commit 2026-03-19 17:02:01 +00:00
Closes #113

Adds a specific `DoesNotExist` handler before the generic `Exception`
block in `update_game_season_stats`. Peewee's `DoesNotExist` (raised
when `StratGame.get_by_id(game_id)` finds no row) previously bubbled
through to the `except Exception` handler which included raw SQL and
params in the 500 detail string. Now returns a clean 404.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude added the
ai-reviewing
label 2026-03-19 17:15:48 +00:00
Claude reviewed 2026-03-19 17:17:01 +00:00
Claude left a comment
Author
Collaborator

AI Code Review

Files Reviewed

  • app/routers_v2/season_stats.py (modified)

Findings

Correctness

  • Fix is correct. StratGame.get_by_id(game_id) raises StratGame.DoesNotExist (a Peewee model-specific subclass of the base peewee.DoesNotExist). The new except DoesNotExist catch uses the base class, which catches all model-specific DoesNotExist subclasses — this works correctly.
  • Exception ordering is correct. The DoesNotExist handler is placed before the generic except Exception block, so it takes precedence as intended.
  • Import is valid. from ..db_engine import DoesNotExist works because db_engine.py uses from peewee import *, pulling DoesNotExist into its namespace. This is the exact same pattern used in current.py, cards.py, teams.py, and dozens of other routers throughout the codebase.
  • Import placement is consistent. The new import is a function-local import alongside the existing from ..services.season_stats import update_season_stats, following the same lazy-import pattern already present in this function.

Security

  • No issues. game_id is a typed int path parameter — no injection risk in the detail=f"Game {game_id} not found" string.
  • No raw SQL or internal state leaked in the 404 response.

Style & Conventions

  • Matches the project pattern for DoesNotExist handling (specific exception before generic 500 fallback).

Suggestions

  • The endpoint docstring (line 47–48) still reads: "Errors from the service are logged but re-raised as 500 so the bot knows to retry." This is now slightly stale — DoesNotExist is returned as a 404 without logging and shouldn't be retried. A one-line docstring update to mention the 404 case would improve accuracy. Non-blocking.

Verdict: APPROVED

Clean, minimal fix. The exception hierarchy is correct, the import follows project conventions, and no security issues are introduced.


Automated review by Claude PR Reviewer (posted as COMMENT due to Gitea self-review restriction)

## AI Code Review ### Files Reviewed - `app/routers_v2/season_stats.py` (modified) ### Findings #### Correctness - **Fix is correct.** `StratGame.get_by_id(game_id)` raises `StratGame.DoesNotExist` (a Peewee model-specific subclass of the base `peewee.DoesNotExist`). The new `except DoesNotExist` catch uses the base class, which catches all model-specific `DoesNotExist` subclasses — this works correctly. - **Exception ordering is correct.** The `DoesNotExist` handler is placed before the generic `except Exception` block, so it takes precedence as intended. - **Import is valid.** `from ..db_engine import DoesNotExist` works because `db_engine.py` uses `from peewee import *`, pulling `DoesNotExist` into its namespace. This is the exact same pattern used in `current.py`, `cards.py`, `teams.py`, and dozens of other routers throughout the codebase. - **Import placement is consistent.** The new import is a function-local import alongside the existing `from ..services.season_stats import update_season_stats`, following the same lazy-import pattern already present in this function. #### Security - No issues. `game_id` is a typed `int` path parameter — no injection risk in the `detail=f"Game {game_id} not found"` string. - No raw SQL or internal state leaked in the 404 response. #### Style & Conventions - Matches the project pattern for `DoesNotExist` handling (specific exception before generic 500 fallback). #### Suggestions - The endpoint docstring (line 47–48) still reads: *"Errors from the service are logged but re-raised as 500 so the bot knows to retry."* This is now slightly stale — `DoesNotExist` is returned as a 404 without logging and shouldn't be retried. A one-line docstring update to mention the 404 case would improve accuracy. Non-blocking. ### Verdict: APPROVED Clean, minimal fix. The exception hierarchy is correct, the import follows project conventions, and no security issues are introduced. --- *Automated review by Claude PR Reviewer (posted as COMMENT due to Gitea self-review restriction)*
Claude added the
ai-reviewed
label 2026-03-19 17:17:24 +00:00
cal merged commit a81bde004b into next-release 2026-03-19 18:18:41 +00:00
cal deleted branch ai/paper-dynasty-database#113 2026-03-19 18:18:41 +00:00
cal removed the
ai-reviewing
label 2026-03-23 15:32:57 +00:00
Sign in to join this conversation.
No description provided.