unslothai/unsloth · warning · HTTPException

Unsupported file type '{ext}'. Allowed: {sorted(config.UPLOA

Error message

Unsupported file type '{ext}'. Allowed: {sorted(config.UPLOAD_EXTS)}

What it means

_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.

Source

Thrown at studio/backend/routes/rag.py:117

def _sanitize_filename(name: str) -> str:
    base = os.path.basename(name or "").strip() or "document"
    base = _SAFE.sub("_", base)
    if len(base) <= 200:
        return base
    # Trim the stem, not the extension: _save_upload gates on the extension, so
    # a plain truncation would reject a long-named .txt as "unsupported".
    stem, ext = os.path.splitext(base)
    if not ext or len(ext) > 32:
        return base[:200]
    return stem[: 200 - len(ext)] + ext


def _persist_upload_stream(source, filename: str, *, empty_detail: str) -> tuple[str, str]:
    """Copy a validated document stream into the managed uploads root."""
    ext = os.path.splitext(filename)[1].lower()
    if ext not in config.UPLOAD_EXTS:
        raise HTTPException(
            status_code = 400,
            detail = f"Unsupported file type '{ext}'. Allowed: {sorted(config.UPLOAD_EXTS)}",
        )
    uploads = ensure_dir(rag_uploads_root())
    stored_path = str(uploads / f"{uuid.uuid4().hex}{ext}")
    size = 0
    cap = config.MAX_UPLOAD_BYTES
    try:
        with open(stored_path, "wb") as out:
            while True:
                block = source.read(1 << 20)
                if not block:
                    break
                size += len(block)
                if cap and size > cap:
                    break
                out.write(block)
    except OSError:

View on GitHub (pinned to 203007d190)

Solutions

  1. Match the detail string's allowlist: convert the file to an allowed format (e.g. export PDF, save as .txt/.md) and re-upload.
  2. If the format is genuinely needed, add its extension to config.UPLOAD_EXTS and ensure the ingestion pipeline can parse it.
  3. Filter the file picker / drag-drop target client-side to allowed extensions before the request.

Example fix

# before
upload('report.docx')  # 400 Unsupported file type '.docx'
# after
upload('report.pdf')   # extension present in config.UPLOAD_EXTS
Defensive patterns

Strategy: validation

Validate before calling

import os
ALLOWED = {'.txt', '.md', '.pdf'}  # mirror config.UPLOAD_EXTS
ext = os.path.splitext(filename)[1].lower()
if ext not in ALLOWED:
    raise ValueError(f'convert {filename} to one of {sorted(ALLOWED)} first')

Type guard

const hasAllowedExt = (name: string): boolean =>
  ALLOWED_EXTS.includes(name.slice(name.lastIndexOf('.')).toLowerCase());

Try / catch

if (!hasAllowedExt(file.name)) { notify(`Only ${ALLOWED_EXTS.join(', ')} supported`); return; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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