{"record":{"id":"d29a442230d64f0f","repo":"unslothai/unsloth","slug":"empty-upload-payload","errorCode":null,"errorMessage":"Empty upload payload","messagePattern":"Empty upload payload","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/hub/services/datasets/local.py","lineNumber":390,"sourceCode":"\n    written = 0\n    upload_complete = False\n    try:\n        with open(stored_path, \"wb\") as f:\n            while chunk := await file.read(LOCAL_UPLOAD_CHUNK_BYTES):\n                written += len(chunk)\n                if written > max_bytes:\n                    raise _upload_too_large(max_label)\n                await asyncio.to_thread(f.write, chunk)\n        upload_complete = True\n    finally:\n        if not upload_complete:\n            with suppress(OSError):\n                stored_path.unlink(missing_ok = True)\n\n    if written == 0:\n        stored_path.unlink(missing_ok = True)\n        raise HTTPException(status_code = 400, detail = \"Empty upload payload\")\n\n    return UploadDatasetResponse(filename = filename, stored_path = str(stored_path))\n\n\ndef list_local_datasets_response() -> LocalDatasetsResponse:\n    return LocalDatasetsResponse(datasets = _build_local_dataset_items())\n","sourceCodeStart":372,"sourceCodeEnd":397,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/hub/services/datasets/local.py#L372-L397","documentation":"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.","triggerScenarios":"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.","commonSituations":"User selects an in-progress download stub; JS creates `new File([], 'x.csv')` as a placeholder; sync-client placeholders again.","solutions":["Check file.size > 0 on the client before allowing submit.","If size looks right, verify the file is not a cloud-sync placeholder — open it locally first.","Log the declared size (the server already early-rejects on `size` when available) to see whether client and disk disagree.","Re-create the empty source file with real content and re-upload."],"exampleFix":"// before\nconst fd = new FormData(); fd.append('file', file);\n// after\nif (!file || file.size === 0) return showError('Choose a non-empty file');\nconst fd = new FormData(); fd.append('file', file);","handlingStrategy":"validation","validationCode":"if (!file || file.size === 0) { showError('Choose a non-empty file'); return; }\nconst fd = new FormData(); fd.append('file', file);","typeGuard":"function isNonEmptyFile(f: unknown): f is File {\n  return f instanceof File && f.size > 0;\n}","tryCatchPattern":"try {\n  await uploadDataset(fd);\n} catch (e) {\n  if (e.status === 400 && /empty/i.test(e.body?.detail ?? '')) {\n    showEmptyFileError(file.name);\n  } else throw e;\n}","preventionTips":["Gate the submit button on file.size > 0 (use the server's declared-size early check as backstop).","Hydrate cloud-sync placeholders before selecting them.","Reject 0-byte files in automated pipelines before they reach the API."],"tags":["upload","empty-file","multipart","http-400"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}