{"record":{"id":"03734ae62a2df5c5","repo":"unslothai/unsloth","slug":"unsupported-format-use-webm-or-gif","errorCode":null,"errorMessage":"Unsupported format. Use webm or gif.","messagePattern":"Unsupported format\\. Use webm or gif\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"studio/backend/routes/video.py","lineNumber":540,"sourceCode":"        media_type = \"video/mp4\",\n        headers = {\"Cache-Control\": \"private, max-age=31536000, immutable\"},\n    )\n\n\n@router.get(\"/video/gallery/{video_id}/export\")\nasync def export_gallery_video(\n    video_id: str,\n    format: str = \"webm\",\n    current_subject: str = Depends(get_current_subject),\n):\n    \"\"\"Download-menu transcodes: WebM (VP9) or GIF, re-encoded on demand from the\n    stored MP4 (which the /file route serves verbatim). 501 with a clear message\n    when the codec/deps for the requested format are missing.\"\"\"\n    from core.inference import video_gallery\n\n    fmt = format.strip().lower()\n    if fmt not in (\"webm\", \"gif\"):\n        raise HTTPException(status_code = 400, detail = \"Unsupported format. Use webm or gif.\")\n    try:\n        path = await asyncio.to_thread(video_gallery.transcode_to_file, video_id, fmt)\n    except RuntimeError as exc:\n        raise HTTPException(status_code = 501, detail = str(exc)) from exc\n    if path is None:\n        raise HTTPException(status_code = 404, detail = \"Video not found.\")\n    from fastapi.responses import FileResponse\n    from starlette.background import BackgroundTask\n\n    def _cleanup() -> None:\n        try:\n            path.unlink(missing_ok = True)\n        except OSError as e:  # noqa: BLE001 -- a leaked temp file must not fail the download\n            logger.debug(f\"Could not remove the export temp file {path}: {e}\")\n\n    # FileResponse streams from disk, so a large VP9 export is never fully resident. The temp file is deleted once sent.\n    return FileResponse(\n        path,","sourceCodeStart":522,"sourceCodeEnd":558,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/video.py#L522-L558","documentation":"400 from the export route: the `format` query parameter, after strip().lower(), is not one of the two supported transcode targets ('webm' or 'gif'). The allowlist exists because each format pulls a specific encoder dependency chain, so anything else is rejected before any disk/CPU work starts.","triggerScenarios":"GET /video/gallery/{id}/export?format=mp4 / ?format=webm%20 / ?format=GIF (lowercased fine) / ?format=mov; a download menu that gained a new option without a backend counterpart; a typo'd or default-missing query param.","commonSituations":"Frontend adds 'Download MP4' to the menu assuming pass-through exists (it doesn't — /file serves the MP4 verbatim, use that instead); URL-encoded whitespace from a template string.","solutions":["Use format=webm or format=gif only.","For the original MP4, link to the /file (or /file-signed) route instead of export.","If a new format is genuinely needed, extend the tuple and add a matching branch in video_gallery.transcode_to_file."],"exampleFix":"# before\n<a href={`/video/gallery/${id}/export?format=mp4`}>Download</a>\n\n# after\n<a href={`/video/gallery/${id}/export?format=webm`}>WebM</a>\n<a href={`/video/gallery/${id}/export?format=gif`}>GIF</a>\n<a href={signedFileUrl}>MP4</a>","handlingStrategy":"validation","validationCode":"const FORMATS = new Set(['webm', 'gif']);\nfunction exportUrl(id: string, fmt: string) {\n  const f = fmt.trim().toLowerCase();\n  if (!FORMATS.has(f)) throw new RangeError(`format must be webm|gif, got ${fmt}`);\n  return `/video/gallery/${id}/export?format=${f}`;\n}","typeGuard":"function isExportFormat(v: string): v is 'webm' | 'gif' {\n  return ['webm', 'gif'].includes(v.trim().toLowerCase());\n}","tryCatchPattern":null,"preventionTips":["Centralize the allowed-format list in one constant shared by menu and URL builder","Use the /file route for raw MP4 instead of inventing format=mp4","Lowercase and trim user/format input before it reaches the URL"],"tags":["http-400","validation","export","transcode"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}