From d1503553eaa42bfdfede46b7d82ae72b5a94989d Mon Sep 17 00:00:00 2001 From: Julian Tabel Date: Sat, 14 Feb 2026 15:24:02 +0100 Subject: [PATCH] Fix route deletion failing due to FK constraint violations Route deletion failed with two integrity errors: 1. route_encounters had no cascade, so SQLAlchemy tried to NULL the non-nullable route_id instead of deleting the rows 2. boss_battles.after_route_id referenced the route being deleted Added cascade="all, delete-orphan" to Route.route_encounters and nulled out boss battle after_route_id references before deletion. Co-Authored-By: Claude Opus 4.6 --- ...-deletion-failing-due-to-missing-cascade.md | 18 ++++++++++++++++++ backend/src/app/api/games.py | 9 ++++++++- backend/src/app/models/route.py | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 .beans/nuzlocke-tracker-h0dr--fix-route-deletion-failing-due-to-missing-cascade.md diff --git a/.beans/nuzlocke-tracker-h0dr--fix-route-deletion-failing-due-to-missing-cascade.md b/.beans/nuzlocke-tracker-h0dr--fix-route-deletion-failing-due-to-missing-cascade.md new file mode 100644 index 0000000..a507376 --- /dev/null +++ b/.beans/nuzlocke-tracker-h0dr--fix-route-deletion-failing-due-to-missing-cascade.md @@ -0,0 +1,18 @@ +--- +# nuzlocke-tracker-h0dr +title: Fix route deletion failing due to missing cascade on route_encounters +status: completed +type: bug +priority: normal +created_at: 2026-02-14T14:19:56Z +updated_at: 2026-02-14T14:23:10Z +--- + +Deleting a route returns 500 due to two FK constraint issues: + +1. `route_encounters.route_id` — missing cascade on the relationship (SQLAlchemy tried to NULL a NOT NULL column) +2. `boss_battles.after_route_id` — references the route being deleted + +## Fix +- Added `cascade="all, delete-orphan"` to `Route.route_encounters` relationship +- Added `update(BossBattle).where(...).values(after_route_id=None)` before deleting the route in the delete endpoint \ No newline at end of file diff --git a/backend/src/app/api/games.py b/backend/src/app/api/games.py index a755ecd..33ac589 100644 --- a/backend/src/app/api/games.py +++ b/backend/src/app/api/games.py @@ -2,7 +2,7 @@ import json from pathlib import Path from fastapi import APIRouter, Depends, HTTPException -from sqlalchemy import delete, select +from sqlalchemy import delete, select, update from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload @@ -373,6 +373,13 @@ async def delete_route( detail="Cannot delete route with existing encounters. Delete the encounters first.", ) + # Null out any boss battle references to this route + await session.execute( + update(BossBattle) + .where(BossBattle.after_route_id == route_id) + .values(after_route_id=None) + ) + await session.delete(route) await session.commit() diff --git a/backend/src/app/models/route.py b/backend/src/app/models/route.py index e44a9c8..9f1bb6b 100644 --- a/backend/src/app/models/route.py +++ b/backend/src/app/models/route.py @@ -25,7 +25,7 @@ class Route(Base): version_group: Mapped["VersionGroup"] = relationship(back_populates="routes") route_encounters: Mapped[list["RouteEncounter"]] = relationship( - back_populates="route" + back_populates="route", cascade="all, delete-orphan" ) encounters: Mapped[list["Encounter"]] = relationship(back_populates="route")