{"record":{"id":"5bf89e4460146833","repo":"unslothai/unsloth","slug":"unsupported-file-type-ext-allowed-sorted-co","errorCode":null,"errorMessage":"Unsupported file type '{ext}'. Allowed: {sorted(config.UPLOAD_EXTS)}","messagePattern":"Unsupported file type '(.+?)'\\. Allowed: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"studio/backend/routes/rag.py","lineNumber":117,"sourceCode":"\ndef _sanitize_filename(name: str) -> str:\n    base = os.path.basename(name or \"\").strip() or \"document\"\n    base = _SAFE.sub(\"_\", base)\n    if len(base) <= 200:\n        return base\n    # Trim the stem, not the extension: _save_upload gates on the extension, so\n    # a plain truncation would reject a long-named .txt as \"unsupported\".\n    stem, ext = os.path.splitext(base)\n    if not ext or len(ext) > 32:\n        return base[:200]\n    return stem[: 200 - len(ext)] + ext\n\n\ndef _persist_upload_stream(source, filename: str, *, empty_detail: str) -> tuple[str, str]:\n    \"\"\"Copy a validated document stream into the managed uploads root.\"\"\"\n    ext = os.path.splitext(filename)[1].lower()\n    if ext not in config.UPLOAD_EXTS:\n        raise HTTPException(\n            status_code = 400,\n            detail = f\"Unsupported file type '{ext}'. Allowed: {sorted(config.UPLOAD_EXTS)}\",\n        )\n    uploads = ensure_dir(rag_uploads_root())\n    stored_path = str(uploads / f\"{uuid.uuid4().hex}{ext}\")\n    size = 0\n    cap = config.MAX_UPLOAD_BYTES\n    try:\n        with open(stored_path, \"wb\") as out:\n            while True:\n                block = source.read(1 << 20)\n                if not block:\n                    break\n                size += len(block)\n                if cap and size > cap:\n                    break\n                out.write(block)\n    except OSError:","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/rag.py#L99-L135","documentation":"_persist_upload_stream() rejects any uploaded document whose lowercase file extension is not in config.UPLOAD_EXTS, raising HTTP 400 with the offending extension and the sorted allowlist. The extension check happens before a temp file is written, so unsupported files never touch disk.","triggerScenarios":"Uploading a document with an extension outside config.UPLOAD_EXTS — e.g. .exe, .zip, .docx when only text/pdf/markdown etc. are allowed — via the browser file upload or a native-path drop.","commonSituations":"User drags a Word/Excel/archive file into the knowledge base; OCR-oriented workflow where the user expects .docx support but the allowlist covers only directly-ingestible text formats; case differences are fine (extension is lowercased) but different formats are not.","solutions":["Match the detail string's allowlist: convert the file to an allowed format (e.g. export PDF, save as .txt/.md) and re-upload.","If the format is genuinely needed, add its extension to config.UPLOAD_EXTS and ensure the ingestion pipeline can parse it.","Filter the file picker / drag-drop target client-side to allowed extensions before the request."],"exampleFix":"# before\nupload('report.docx')  # 400 Unsupported file type '.docx'\n# after\nupload('report.pdf')   # extension present in config.UPLOAD_EXTS","handlingStrategy":"validation","validationCode":"import os\nALLOWED = {'.txt', '.md', '.pdf'}  # mirror config.UPLOAD_EXTS\next = os.path.splitext(filename)[1].lower()\nif ext not in ALLOWED:\n    raise ValueError(f'convert {filename} to one of {sorted(ALLOWED)} first')","typeGuard":"const hasAllowedExt = (name: string): boolean =>\n  ALLOWED_EXTS.includes(name.slice(name.lastIndexOf('.')).toLowerCase());","tryCatchPattern":"if (!hasAllowedExt(file.name)) { notify(`Only ${ALLOWED_EXTS.join(', ')} supported`); return; }","preventionTips":["Set the file input's accept attribute to the allowed extensions.","Re-check the allowlist after backend upgrades — it is config-driven and can change.","Offer in-app conversion (export to PDF/text) instead of letting users hit the 400."],"tags":["http-400","file-upload","extension-allowlist","rag","studio-backend"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}