{"record":{"id":"a1c492d05310a8fd","repo":"unslothai/unsloth","slug":"dropped-file-could-not-be-read","errorCode":null,"errorMessage":"Dropped file could not be read.","messagePattern":"Dropped file could not be read\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/rag.py","lineNumber":188,"sourceCode":"            lease,\n            operation = \"attach\",\n            expected_kind = \"attachment\",\n            expected_path_type = \"file\",\n            allowed_suffixes = sorted(config.UPLOAD_EXTS),\n        )\n    except NativePathLeaseError as exc:\n        raise HTTPException(status_code = 400, detail = str(exc)) from exc\n\n    filename = _sanitize_filename(grant.canonical_path.name)\n    try:\n        with open(grant.canonical_path, \"rb\") as source:\n            return _persist_upload_stream(\n                source,\n                filename,\n                empty_detail = \"Dropped file is empty.\",\n            )\n    except OSError as exc:\n        raise HTTPException(status_code = 400, detail = \"Dropped file could not be read.\") from exc\n\n\ndef _resolve_document_upload(\n    file: UploadFile | None, native_path_lease: str | None\n) -> tuple[str, str]:\n    if native_path_lease:\n        return _save_native_path_upload(native_path_lease)\n    if file is None:\n        raise HTTPException(status_code = 400, detail = \"No file was provided.\")\n    return _save_upload(file)\n\n\ndef _remove_stored_upload(stored_path: str | None) -> None:\n    \"\"\"Best-effort cleanup for files saved by _save_upload.\"\"\"\n    if not stored_path:\n        return\n    try:\n        uploads = os.path.realpath(str(rag_uploads_root()))","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/rag.py#L170-L206","documentation":"In the native-path attach flow, after the lease verifies, the backend opens grant.canonical_path to copy the file into the managed uploads root. If open() or the streaming read raises OSError (file deleted, permissions changed, I/O error, unreadable removable media), it is converted to HTTP 400 'Dropped file could not be read.' — the lease was valid but the bytes are gone.","triggerScenarios":"File removed, renamed, locked (Windows), on unmounted external media, or with read permission revoked between the user dropping it and the backend opening it.","commonSituations":"User drops a file from a USB drive that gets disconnected; antivirus/quarantine removes the file; the file lives in a synchronized folder that renames it during upload; macOS sandbox denies read after the lease.","solutions":["Verify the file still exists and is readable (os.access(path, R_OK)) right before upload and re-drop if not.","Re-mount / re-attach the external media and repeat the drop.","Copy the file to a local stable location before dropping if it lives on flaky storage."],"exampleFix":"# before\ndrop_file('/mnt/usb/report.pdf')  # USB unplugged -> 400\n# after\nimport os\nif not os.access('/mnt/usb/report.pdf', os.R_OK):\n    raise SystemExit('Re-attach the drive, then drop the file again')","handlingStrategy":"try-catch","validationCode":"import os\nif not os.path.isfile(path) or not os.access(path, os.R_OK):\n    raise RuntimeError('file unreadable; re-select it')","typeGuard":null,"tryCatchPattern":"if (res.status === 400 && detail === 'Dropped file could not be read.') { promptReDrop(); }","preventionTips":["Drop files from stable local storage, not removable/network mounts.","Re-drop promptly after selection to shrink the race window.","On Windows, ensure no other process holds an exclusive lock on the file."],"tags":["http-400","native-path-lease","file-io","rag","studio-backend"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}