bug: GET /refractor/cards returns count: null with out-of-range tier filter #182

Open
opened 2026-04-06 05:35:44 +00:00 by cal · 1 comment
Owner

Description

GET /api/v2/refractor/cards?team_id=31&tier=99 returns {"count": null, "items": []} instead of {"count": 0, "items": []}.

Valid tier values are 0–4. When an out-of-range value is passed, the count field comes back as null rather than 0. The items array is correctly empty.

Steps to Reproduce

curl -s "https://pddev.manticorum.com/api/v2/refractor/cards?team_id=31&tier=99" \
  -H "Authorization: Bearer $TOKEN"

Actual: {"count": null, "items": []}
Expected: {"count": 0, "items": []} or a 422 validation error rejecting tier values outside 0–4

Impact

Low — cosmetic/contract issue. The bot handles empty responses gracefully, but API consumers relying on count being an integer will get None.

Found during REF-API integration testing (2026-04-06).

## Description `GET /api/v2/refractor/cards?team_id=31&tier=99` returns `{"count": null, "items": []}` instead of `{"count": 0, "items": []}`. Valid tier values are 0–4. When an out-of-range value is passed, the count field comes back as `null` rather than `0`. The `items` array is correctly empty. ## Steps to Reproduce ```bash curl -s "https://pddev.manticorum.com/api/v2/refractor/cards?team_id=31&tier=99" \ -H "Authorization: Bearer $TOKEN" ``` **Actual:** `{"count": null, "items": []}` **Expected:** `{"count": 0, "items": []}` or a 422 validation error rejecting tier values outside 0–4 ## Impact Low — cosmetic/contract issue. The bot handles empty responses gracefully, but API consumers relying on `count` being an integer will get `None`. Found during REF-API integration testing (2026-04-06).
Claude added the
ai-working
label 2026-04-06 06:00:58 +00:00
Claude added the
ai-pr-opened
label 2026-04-06 06:08:04 +00:00
Collaborator

Fixed in PR #184.

Root cause: Peewee 3.17.9's .count() on a complex three-table JOIN (RefractorCardState → RefractorTrack → Player LEFT OUTER) can return None rather than 0 when the query matches zero rows.

Fix: total = query.count() or 0 in app/routers_v2/refractor.py — one-line defensive guard ensuring count is always an integer.

Note on the exact repro (tier=99): The tier parameter already has ge=0, le=4 FastAPI validation, so tier=99 now returns a 422 before the query runs. The or 0 guard covers all other zero-result scenarios (valid tier with no matching cards, etc.).

Fixed in PR #184. **Root cause:** Peewee 3.17.9's `.count()` on a complex three-table JOIN (RefractorCardState → RefractorTrack → Player LEFT OUTER) can return `None` rather than `0` when the query matches zero rows. **Fix:** `total = query.count() or 0` in `app/routers_v2/refractor.py` — one-line defensive guard ensuring `count` is always an integer. **Note on the exact repro (`tier=99`):** The `tier` parameter already has `ge=0, le=4` FastAPI validation, so `tier=99` now returns a 422 before the query runs. The `or 0` guard covers all other zero-result scenarios (valid tier with no matching cards, etc.).
Claude removed the
ai-working
label 2026-04-06 06:08:11 +00:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: cal/paper-dynasty-database#182
No description provided.