odysseus-dev/odysseus · warning · HTTPException

Album not found

Error message

Album not found

What it means

HTTP 404 from _get_or_404_album when no GalleryAlbum row exists with the given album_id in the database. This is the 'does not exist' branch; the separate owner check (609) is the 'exists but not yours' branch, deliberately returning the same status and message to avoid leaking album existence.

Source

Thrown at routes/gallery/gallery_routes.py:2127

            enhanced = img.filter(ImageFilter.MedianFilter(size=3))  # light denoise
            enhanced = enhanced.filter(ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3))  # sharpen
            enhanced = ImageEnhance.Contrast(enhanced).enhance(1.15)  # slight contrast boost
            enhanced = ImageEnhance.Color(enhanced).enhance(1.1)  # subtle color boost
            enhanced = ImageEnhance.Brightness(enhanced).enhance(1.05)  # slight brightness lift

            buf = io.BytesIO()
            enhanced.save(buf, format="PNG")
            return {"image": base64.b64encode(buf.getvalue()).decode(), "method": "pil"}
        except Exception:
            logger.exception("enhance_face: failed")
            raise HTTPException(500, "Face enhancement failed")

    # ---- Album management (path-param routes) ----

    def _get_or_404_album(db, album_id: str, user):
        album = db.query(GalleryAlbum).filter(GalleryAlbum.id == album_id).first()
        if not album:
            raise HTTPException(404, "Album not found")
        if not user or album.owner != user:
            raise HTTPException(404, "Album not found")
        return album

    def _get_or_404_image(db, image_id: str, user):
        img = db.query(GalleryImage).filter(GalleryImage.id == image_id).first()
        if not img:
            raise HTTPException(404, "Image not found")
        if not user or img.owner != user:
            raise HTTPException(404, "Image not found")
        return img

    @router.put("/api/gallery/albums/{album_id}")
    async def update_album(request: Request, album_id: str):
        user = get_current_user(request)
        data = await request.json()
        db = SessionLocal()
        try:

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Re-fetch the album list (GET /api/gallery/albums) and use a current ID
  2. Treat 404 on album ops as 'refresh state' in the UI rather than an error dialog
  3. Confirm the album was not deleted by another session sharing the account

Example fix

# client
resp = requests.put(f'{base}/api/gallery/albums/{aid}', json=body)
if resp.status_code == 404:
    albums = requests.get(f'{base}/api/gallery/albums').json()  # refresh
    aid = pick_album(albums)
Defensive patterns

Strategy: validation

Validate before calling

def album_exists(album_id: str) -> bool:
    albums = requests.get(f'{base}/api/gallery/albums', headers=hdrs, timeout=30).json()
    return any(a.get('id') == album_id for a in albums.get('albums', albums))

Try / catch

try:
    update_album(album_id, name='Holiday')
except HTTPError as e:
    if e.response.status_code == 404:
        albums = refresh_album_cache()
        album_id = first(a['id'] for a in albums if a['name'] == 'Holiday') or create_album('Holiday')
        update_album(album_id, name='Holiday')
    else:
        raise

Prevention

When it happens

Trigger: PUT/DELETE /api/gallery/albums/{album_id} (and image-in-album ops) with an ID from a deleted album, a stale client cache, or a typo/truncated UUID.

Common situations: Album deleted in another tab or by another session; client holds an old album list; database reset/re-migrated so IDs no longer resolve.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/741355a4e2f7894c. Report an issue: GitHub.