{"record":{"id":"8ffeaf49e16c53dd","repo":"unslothai/unsloth","slug":"unsupported-file-type-ext-allowed-join","errorCode":null,"errorMessage":"Unsupported file type: {ext}. Allowed: {', '.join(sorted(UNSTRUCTURED_ALLOWED_EXTS))}","messagePattern":"Unsupported file type: (.+?)\\. Allowed: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/data_recipe/seed.py","lineNumber":445,"sourceCode":"    for f in block_dir.iterdir():\n        if not f.is_file():\n            continue\n        if f.name.endswith(\".extracted.txt\") or f.name.endswith(\".meta.json\"):\n            continue\n        total += f.stat().st_size\n    return total\n\n\n@router.post(\"/seed/upload-unstructured-file\")\nasync def upload_unstructured_file(\n    file: UploadFile = FastAPIFile(...), block_id: str = Form(...)\n) -> UnstructuredFileUploadResponse:\n    _validate_safe_id(block_id, \"block_id\")\n\n    original_filename = file.filename or \"upload\"\n    ext = Path(original_filename).suffix.lower()\n    if ext not in UNSTRUCTURED_ALLOWED_EXTS:\n        raise HTTPException(\n            400,\n            f\"Unsupported file type: {ext}. Allowed: {', '.join(sorted(UNSTRUCTURED_ALLOWED_EXTS))}\",\n        )\n\n    content = await file.read()\n    size_bytes = len(content)\n\n    if size_bytes == 0:\n        raise HTTPException(400, \"Empty file not allowed\")\n\n    if size_bytes > UNSTRUCTURED_RECIPE_UPLOAD_MAX_BYTES:\n        raise HTTPException(\n            413,\n            f\"File too large ({size_bytes} bytes). Maximum is {UNSTRUCTURED_RECIPE_UPLOAD_MAX_LABEL}.\",\n        )\n\n    block_dir = UNSTRUCTURED_UPLOAD_ROOT / block_id\n    ensure_dir(block_dir)","sourceCodeStart":427,"sourceCodeEnd":463,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/data_recipe/seed.py#L427-L463","documentation":"HTTP 400 raised by POST /seed/upload-unstructured-file when the uploaded file's lowercased extension is not in UNSTRUCTURED_ALLOWED_EXTS = {.pdf, .docx, .txt, .md}. The extension comes from the original filename's suffix; other document formats are rejected before the bytes are even read.","triggerScenarios":"Uploading .docx works, but .doc, .rtf, .odt, .pptx, .html, or an extension-less file fails immediately with this 400.","commonSituations":"Legacy .doc files from Word; user assumes 'any document' works; macOS 'file.pdf.download' style names; uppercase handled (code lowercases), so the failure is always a genuinely unsupported format.","solutions":["Convert the document to .pdf, .docx, .txt, or .md before upload.","For .doc, re-save as .docx in Word/LibreOffice or export as PDF.","Ensure the filename retains its extension — do not strip it when staging uploads."],"exampleFix":"# before\nlibreoffice --convert-to doc old.doc  # still rejected\n\n# after\nlibreoffice --convert-to pdf old.doc  # .pdf is allowed","handlingStrategy":"validation","validationCode":"const ALLOWED = new Set(['.pdf', '.docx', '.txt', '.md']);\nconst ext = file.name.slice(file.name.lastIndexOf('.')).toLowerCase();\nif (!ALLOWED.has(ext)) throw new Error(`unsupported: ${ext}; convert to pdf/docx/txt/md`);","typeGuard":"function isAllowedDoc(name: string): boolean {\n  return ['.pdf', '.docx', '.txt', '.md'].includes(name.slice(name.lastIndexOf('.')).toLowerCase());\n}","tryCatchPattern":"On 400 'Unsupported file type', filter the file out of the batch, tell the user which files need conversion, and upload the rest.","preventionTips":["Set accept='.pdf,.docx,.txt,.md' on the document upload input.","Convert legacy formats (.doc, .rtf) upstream in your ingestion pipeline."],"tags":["file-type","upload","unstructured","http-400"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}