From 104f29f5e30ee8c2f367533e05a043d9eac6c177 Mon Sep 17 00:00:00 2001 From: Ty Balascio Date: Fri, 25 Sep 2026 20:41:00 -0700 Subject: [PATCH] fix(backend): clear a re-uploaded photo by id, not id+slab slab_photos.id is a global primary key and photo ids are derived from the slab id, so scoping the replace to the slab let a retried or concurrent upload of the same draft hit UNIQUE(id) and 500. Clear the id unconditionally. --- backend/photos.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/photos.py b/backend/photos.py index 708fdd9..cf664a3 100644 --- a/backend/photos.py +++ b/backend/photos.py @@ -59,8 +59,10 @@ async def upload_photo( proc_bytes = await processed.read() if processed is not None else None if not orig_bytes: return JSONResponse(status_code=400, content=_error("validation", "original photo is empty")) - # Replace any existing photo with the same id on this slab (re-upload). - conn.execute("DELETE FROM slab_photos WHERE id=? AND slab_id=?", (photo_id, slab_id)) + # slab_photos.id is a global primary key and photo ids are derived from the + # slab id, so a re-upload must clear the id regardless of slab: a retried or + # concurrent upload of the same draft would otherwise hit UNIQUE(id). + conn.execute("DELETE FROM slab_photos WHERE id=?", (photo_id,)) seq_val = seq if seq is not None else _next_seq(conn, slab_id) conn.execute( "INSERT INTO slab_photos(id, slab_id, seq, is_calibration, role, original_blob, processed_blob, created_at) "