{"record":{"id":"b093d23ff4554522","repo":"odysseus-dev/odysseus","slug":"unknown-wipe-kind-kind-r","errorCode":null,"errorMessage":"Unknown wipe kind: {kind!r}","messagePattern":"Unknown wipe kind: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"routes/admin_wipe/admin_wipe_routes.py","lineNumber":166,"sourceCode":"            if kind == \"gallery\":\n                count = db.query(GalleryImage).count() + db.query(GalleryAlbum).count()\n                db.query(GalleryImage).delete()\n                db.query(GalleryAlbum).delete()\n                db.commit()\n                # Also drop the upload dir so disk doesn't keep orphans.\n                _rmtree_quiet(GALLERY_DIR)\n                _rmtree_quiet(GALLERY_UPLOADS_DIR)\n                return {\"status\": \"deleted\", \"kind\": kind, \"count\": count}\n\n            if kind == \"calendar\":\n                # Events FK calendars — clear children first, then both.\n                db.query(CalendarEvent).delete()\n                count = db.query(CalendarCal).count()\n                db.query(CalendarCal).delete()\n                db.commit()\n                return {\"status\": \"deleted\", \"kind\": kind, \"count\": count}\n\n            raise HTTPException(400, f\"Unknown wipe kind: {kind!r}\")\n        except HTTPException:\n            raise\n        except Exception as e:\n            db.rollback()\n            logger.exception(f\"Wipe {kind} failed\")\n            raise HTTPException(500, f\"Wipe {kind} failed: {e}\")\n        finally:\n            db.close()\n\n    return router\n","sourceCodeStart":148,"sourceCodeEnd":177,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/routes/admin_wipe/admin_wipe_routes.py#L148-L177","documentation":"HTTPException(400) from the admin wipe endpoint: the 'kind' path/query value did not match any of the handled wipe branches (the if-chain covering gallery, calendar, etc.) and execution fell through to the explicit unknown-kind guard.","triggerScenarios":"POST/DELETE to the wipe endpoint with kind=typo (e.g. 'galery'), a plural form ('calendars'), or a kind that exists in the app but has no wipe branch (e.g. 'tokens').","commonSituations":"Guessing endpoint payloads without reading the route; versions where supported kinds changed; shell quoting dropping or mangling the kind value.","solutions":["Use the exact kind strings implemented in the route's if-chain (read admin_wipe_routes.py)","Check the API docs/OpenAPI schema for the wipe endpoint's accepted values","If a new kind should be wipeable, add an explicit branch rather than guessing"],"exampleFix":"# before\ncurl -X POST /api/admin/wipe?kind=calendars\n# after\ncurl -X POST /api/admin/wipe?kind=calendar","handlingStrategy":"validation","validationCode":"SUPPORTED = {'gallery','calendar', ...}  # mirror the route's if-chain\nif kind not in SUPPORTED:\n    raise ValueError(f'kind must be one of {sorted(SUPPORTED)}')","typeGuard":"def is_supported_wipe_kind(kind: str) -> bool:\n    return kind in {'gallery','calendar'}  # keep in sync with route","tryCatchPattern":"try:\n    client.post(f'/api/admin/wipe?kind={kind}')\nexcept HTTPError as e:\n    if e.response.status_code == 400 and 'Unknown wipe kind' in e.response.text:\n        raise ValueError(f'bad kind: {kind}') from e\n    raise","preventionTips":["Read the route source or OpenAPI schema before scripting admin wipes","Pin the accepted kind list in a shared constant client and server can import","Dry-run/list endpoint variants before destructive calls"],"tags":["http","admin","validation","fastapi"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}