unslothai/unsloth · error · HTTPException

Image not found.

Error message

Image not found.

What it means

HTTP 404 from the dataset image serving route: the dataset folder resolved and the filename passed all safety checks, but image_path.is_file() is false — the named image does not exist (deleted, renamed, or never uploaded). Raised before thumbnail generation, so no thumb is produced either.

Source

Thrown at studio/backend/routes/training.py:3817

    return await asyncio.to_thread(scan)


@router.get("/diffusion/dataset/{name}/image/{filename}")
async def get_diffusion_dataset_image(
    name: str,
    filename: str,
    thumb: Optional[int] = None,
    current_subject: str = Depends(get_current_subject),
):
    """Serve a dataset image. ``?thumb=<px>`` returns a cached downscaled JPEG (regenerated
    when the source is newer), used by the labeling grid to stay light."""
    from fastapi.responses import FileResponse

    folder = _resolve_dataset_folder(name)
    image_path = _safe_dataset_image_path(folder, filename)
    if not image_path.is_file():
        raise HTTPException(status_code = 404, detail = "Image not found.")
    if not thumb:
        return FileResponse(str(image_path))

    size = max(32, min(1024, int(thumb)))

    def make_thumb() -> Path:
        from PIL import Image

        thumbs_dir = folder / _THUMBS_DIRNAME
        thumbs_dir.mkdir(exist_ok = True)
        # Key on the full filename, not the stem: two images sharing a stem would collide on one cache file and the mtime-newer entry would be served for both.
        thumb_path = thumbs_dir / f"{image_path.name}_{size}.jpg"
        src_mtime = image_path.stat().st_mtime
        if thumb_path.is_file() and thumb_path.stat().st_mtime >= src_mtime:
            return thumb_path
        with Image.open(image_path) as im:
            im = im.convert("RGB")
            im.thumbnail((size, size), Image.LANCZOS)

View on GitHub (pinned to 203007d190)

Solutions

  1. Refresh the dataset image list (GET /diffusion/dataset/{name}/images) and use current filenames.
  2. If the file was renamed, use the new name; if deleted, re-upload it.
  3. Cache-bust or expire stale client asset URLs after delete operations.

Example fix

// before
<img src={`/training/diffusion/dataset/${name}/image/${fname}?thumb=256`} />
// after — verify existence first / on error remove from grid
const imgs = await api.listImages(name);
const ok = imgs.some(i => i.name === fname);
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def image_served(folder: Path, filename: str) -> bool:
    return (folder / filename).is_file()

Type guard

def is_image_not_found(exc: HTTPException) -> bool:
    return exc.status_code == 404 and exc.detail == 'Image not found.'

Try / catch

try:
    r = await client.get(image_url)
except httpx.HTTPStatusError as e:
    if e.response.status_code == 404:
        removeFromGrid(filename)  # prune stale entry, don't retry
        return
    raise

Prevention

When it happens

Trigger: GET /training/diffusion/dataset/{name}/image/{filename} where the file is absent: a labeling grid holding stale URLs after images were deleted in another tab, a renamed file, or a typo'd filename.

Common situations: Two tabs editing one dataset (delete in one, grid in the other); scripts referencing files after a re-import replaced the set; client caches serving old asset URLs; case-sensitivity mismatch on case-folding filesystems.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/5238b4b36627d396. Report an issue: GitHub.