{"record":{"id":"730eafcca1e0714c","repo":"unslothai/unsloth","slug":"native-path-grant-is-required","errorCode":null,"errorMessage":"Native path grant is required.","messagePattern":"Native path grant is required\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/rag.py","lineNumber":177,"sourceCode":"\ndef _save_native_path_upload(lease: str) -> tuple[str, str]:\n    \"\"\"Persist a desktop drop; returns (stored_path, filename).\n\n    The webview never gets to name a path directly: Rust signs the path it saw and we\n    re-verify + re-stat that grant here before reading a byte.\n    \"\"\"\n    from utils.native_path_leases import NativePathLeaseError, verify_native_path_lease\n\n    try:\n        grant = verify_native_path_lease(\n            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)","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/rag.py#L159-L195","documentation":"When attaching a file by native path (desktop drag-drop), the backend must first verify a signed native-path lease via verify_native_path_lease() with operation='attach', kind='attachment', path_type='file', and suffixes limited to config.UPLOAD_EXTS. Any NativePathLeaseError — including 'Native path grant is required.' when the lease token is absent, malformed, expired, or fails verification — surfaces as HTTP 400 with the lease error's text.","triggerScenarios":"Calling the attach endpoint with a native_path_lease that is missing, empty, has a bad signature, names the wrong operation/kind/path-type, points at a file with a disallowed extension, or was issued for a different path or after expiry.","commonSituations":"Frontend sends the raw path instead of requesting a lease from the desktop bridge; lease expired between selection and upload; replaying an old lease after the file was replaced; mismatch between the lease's granted kind and the endpoint's expectation.","solutions":["Request a fresh lease from the native-path lease issuer for the exact file right before upload and pass it unchanged.","Confirm the lease is for operation 'attach', kind 'attachment', path type 'file', and the file's extension is in config.UPLOAD_EXTS.","Do not cache or reuse leases across sessions; re-request after expiry errors."],"exampleFix":"// before\nbody: { nativePathLease: filePath } // raw path, no lease -> 400\n// after\nconst lease = await bridge.requestLease(filePath, { kind: 'attachment', operation: 'attach' });\nbody: { nativePathLease: lease.token }","handlingStrategy":"validation","validationCode":"const lease = await bridge.requestLease(path, { kind: 'attachment', operation: 'attach', pathType: 'file' });\nif (!lease?.token) throw new Error('no lease granted');","typeGuard":null,"tryCatchPattern":"if (res.status === 400 && /Native path grant/.test(detail)) { re_request_lease(path); }","preventionTips":["Never send raw filesystem paths; always go through the lease broker.","Use the lease immediately — they expire; re-request on 400 rather than caching.","Match lease kind/operation/path_type to the endpoint you are calling."],"tags":["http-400","native-path-lease","file-attach","authorization","rag","studio-backend"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}