unslothai/unsloth · error · HTTPException

Empty upload payload

Error message

Empty upload payload

What it means

HTTP 400 from multipart upload when the streamed file copied to storage with zero bytes written (written == 0). The stored path is unlinked first, keeping the uploads dir clean. Equivalent of 815 for the browser-upload path: the part existed but carried no content.

Source

Thrown at studio/backend/hub/services/datasets/local.py:390

    written = 0
    upload_complete = False
    try:
        with open(stored_path, "wb") as f:
            while chunk := await file.read(LOCAL_UPLOAD_CHUNK_BYTES):
                written += len(chunk)
                if written > max_bytes:
                    raise _upload_too_large(max_label)
                await asyncio.to_thread(f.write, chunk)
        upload_complete = True
    finally:
        if not upload_complete:
            with suppress(OSError):
                stored_path.unlink(missing_ok = True)

    if written == 0:
        stored_path.unlink(missing_ok = True)
        raise HTTPException(status_code = 400, detail = "Empty upload payload")

    return UploadDatasetResponse(filename = filename, stored_path = str(stored_path))


def list_local_datasets_response() -> LocalDatasetsResponse:
    return LocalDatasetsResponse(datasets = _build_local_dataset_items())

View on GitHub (pinned to 203007d190)

Solutions

  1. Check file.size > 0 on the client before allowing submit.
  2. If size looks right, verify the file is not a cloud-sync placeholder — open it locally first.
  3. Log the declared size (the server already early-rejects on `size` when available) to see whether client and disk disagree.
  4. Re-create the empty source file with real content and re-upload.

Example fix

// before
const fd = new FormData(); fd.append('file', file);
// after
if (!file || file.size === 0) return showError('Choose a non-empty file');
const fd = new FormData(); fd.append('file', file);
Defensive patterns

Strategy: validation

Validate before calling

if (!file || file.size === 0) { showError('Choose a non-empty file'); return; }
const fd = new FormData(); fd.append('file', file);

Type guard

function isNonEmptyFile(f: unknown): f is File {
  return f instanceof File && f.size > 0;
}

Try / catch

try {
  await uploadDataset(fd);
} catch (e) {
  if (e.status === 400 && /empty/i.test(e.body?.detail ?? '')) {
    showEmptyFileError(file.name);
  } else throw e;
}

Prevention

When it happens

Trigger: Submitting a 0-byte file part; a client constructing FormData with an empty Blob or empty File; some browsers reporting a File handle for a placeholder that streams zero bytes.

Common situations: User selects an in-progress download stub; JS creates `new File([], 'x.csv')` as a placeholder; sync-client placeholders again.

Related errors


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