{"record":{"id":"583ec255f58b0c80","repo":"unslothai/unsloth","slug":"not-an-image-file-allowed-exts","errorCode":null,"errorMessage":"Not an image file. Allowed: {exts}","messagePattern":"Not an image file\\. Allowed: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/training.py","lineNumber":3676,"sourceCode":"    if width > _MAX_TRAINING_IMAGE_SIDE or height > _MAX_TRAINING_IMAGE_SIDE:\n        raise HTTPException(\n            status_code = 400,\n            detail = (\n                f\"Image '{original_name}' is too large ({width}x{height}); maximum is \"\n                f\"{_MAX_TRAINING_IMAGE_SIDE}px per side.\"\n            ),\n        )\n\n\ndef _safe_dataset_image_path(folder: Path, filename: str) -> Path:\n    \"\"\"Resolve ``filename`` to an image path strictly inside ``folder``. Rejects any path\n    separators / traversal / null bytes and non-image extensions.\"\"\"\n    raw = filename or \"\"\n    if \"/\" in raw or \"\\\\\" in raw or \"..\" in raw or \"\\x00\" in raw or raw != Path(raw).name:\n        raise HTTPException(status_code = 400, detail = \"Invalid image filename.\")\n    if Path(raw).suffix.lower() not in _DIFFUSION_DATASET_IMAGE_EXTS:\n        exts = \", \".join(sorted(_DIFFUSION_DATASET_IMAGE_EXTS))\n        raise HTTPException(status_code = 400, detail = f\"Not an image file. Allowed: {exts}\")\n    path = folder / raw\n    # Defense in depth: the real path must stay under the dataset folder.\n    try:\n        path.resolve().relative_to(folder.resolve())\n    except ValueError:\n        raise HTTPException(status_code = 400, detail = \"Invalid image filename.\")\n    return path\n\n\ndef _load_metadata_captions(folder: Path) -> dict[str, str]:\n    \"\"\"Read metadata.jsonl / captions.jsonl into {file_name: caption}, mirroring the\n    trainer's discovery (keys file_name/video/image/file; caption in the ``text`` column).\"\"\"\n    import json\n\n    out: dict[str, str] = {}\n    for meta_name in (\"metadata.jsonl\", \"captions.jsonl\"):\n        meta_path = folder / meta_name\n        if not meta_path.is_file():","sourceCodeStart":3658,"sourceCodeEnd":3694,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/training.py#L3658-L3694","documentation":"HTTP 400 from _safe_dataset_image_path: the filename's extension (lowercased) is not in _DIFFUSION_DATASET_IMAGE_EXTS = {'.png','.jpg','.jpeg','.webp','.bmp'}. The name passed the traversal checks but is not an image by extension — the dataset image routes only serve those five types.","triggerScenarios":"Requesting an image-scoped route with e.g. 'clip.mp4', 'labels.json', 'cat.gif', 'img.tiff', or a file with no extension. Example: GET /training/diffusion/dataset/myset/image/notes.txt.","commonSituations":"Forgetting that videos/clips are managed by different endpoints than stills; trying to fetch a .tiff/.gif/.avif that the trainer does not accept; probing for sidecar files (.txt captions, metadata.jsonl) through the image route.","solutions":["Use an allowed extension: convert the file (e.g. magick in.gif out.png) before requesting/uploading it.","Fetch captions via the dataset listing endpoints, not the image route; clips go through the clip endpoints.","When uploading, rename or convert non-supported types instead of forcing them through."],"exampleFix":"# convert a non-allowed type into the accepted set\nmagick input.gif output.png","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\nALLOWED = {'.png', '.jpg', '.jpeg', '.webp', '.bmp'}\n\ndef is_allowed_image_name(name: str) -> bool:\n    return Path(name).suffix.lower() in ALLOWED","typeGuard":"def is_extension_error(exc: HTTPException) -> bool:\n    return exc.status_code == 400 and str(exc.detail).startswith('Not an image file.')","tryCatchPattern":"try:\n    await serve_image(name, filename)\nexcept HTTPException as e:\n    if e.status_code == 400 and str(e.detail).startswith('Not an image file.'):\n        convert_to_png_and_retry(filename)\n    raise","preventionTips":["Filter client-side file pickers to the five allowed extensions.","Convert .gif/.tiff/.avif assets during dataset preparation."],"tags":["validation","file-type","fastapi","http-400"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}