unslothai/unsloth · error · NativePathLeaseError
Native path changed after it was selected.
Error message
Native path changed after it was selected.
What it means
The file's current size (st_size) differs from the size_bytes recorded in the signed grant, so the backend concludes the path changed after the user selected it. _validate_current_stat() pins size and mtime to detect any mutation between selection and use. This protects read consistency and prevents TOCTOU swaps of file content under a valid-looking lease.
Source
Thrown at studio/backend/utils/native_path_leases.py:362
grant: NativePathGrant, identity_options: tuple[tuple[int, int], ...]
) -> tuple[int, int] | None:
try:
st = os.lstat(grant.canonical_path)
except OSError as exc:
raise NativePathLeaseError("Native path is no longer accessible.") from exc
if _stat_module.S_ISLNK(st.st_mode):
raise NativePathLeaseError("Native path is no longer a regular file.")
if grant.path_type == "file":
if not _stat_module.S_ISREG(st.st_mode):
raise NativePathLeaseError("Native path is no longer a regular file.")
elif grant.path_type == "directory":
if not _stat_module.S_ISDIR(st.st_mode):
raise NativePathLeaseError("Native path is no longer a directory.")
else:
raise NativePathLeaseError("Native path grant has an unsupported path type.")
if grant.size_bytes is not None and st.st_size != grant.size_bytes:
raise NativePathLeaseError("Native path changed after it was selected.")
current_modified_ms = int(st.st_mtime_ns // 1_000_000)
if grant.modified_ms is not None and current_modified_ms != grant.modified_ms:
raise NativePathLeaseError("Native path changed after it was selected.")
if grant.path_kind == "document-folder" and not identity_options:
raise NativePathLeaseError("Native path grant is missing its folder identity.")
current_identity = (st.st_dev, st.st_ino)
expected_identity = _runtime_identity(identity_options)
if expected_identity is not None and current_identity != expected_identity:
raise NativePathLeaseError("Native path changed after it was selected.")
return current_identity if expected_identity is not None else None
def _consume_nonce(nonce: str, expires_at_ms: int) -> None:
now_ms = int(time.time() * 1000)
with _REPLAY_LOCK:
for key, expiry in list(_USED_NONCES.items()):
if expiry <= now_ms:
_USED_NONCES.pop(key, None)View on GitHub (pinned to 203007d190)
Solutions
- Wait for writes to finish, then re-select the file to get a grant with the final size.
- stat -c '%s' <path> and compare with size_bytes from the decoded payload to confirm which snapshot is stale.
- Exclude actively-written files from selection (copy to a stable location first), then re-select.
- For sync clients, wait for the 'synced' state before picking the file.
Example fix
# before pick file while downloader still writes it -> size grows -> grant stale # after $ while [ "$(stat -c %s model.gguf)" != "$LAST" ]; do LAST=$(stat -c %s model.gguf); sleep 2; done # download settled; re-select file and resubmit
Defensive patterns
Strategy: validation
Validate before calling
import base64, json, os
def size_matches_grant(lease: str) -> bool:
payload = json.loads(base64.urlsafe_b64decode(lease.split('.')[0] + '=='))
expected = payload.get('size_bytes')
if expected is None:
return True
try:
return os.lstat(payload['canonical_path']).st_size == int(expected)
except OSError:
return False Try / catch
try:
grant = verify_native_path_lease(lease, operation='read')
except NativePathLeaseError as exc:
if 'changed after it was selected' in str(exc):
lease = request_fresh_grant() # file mutated; re-pin size/mtime
grant = verify_native_path_lease(lease, operation='read')
else:
raise Prevention
- Only select files once all writers (downloaders, sync clients) have finished.
- Mint the grant as the last step before the API call, not at page load.
- Copy in-flight files to a stable location and select the copy.
When it happens
Trigger: verify_native_path_lease() where grant.size_bytes is not None and st.st_size != grant.size_bytes: the file was appended to, truncated, overwritten, or replaced with a different-sized file between the picker and job run; a still-downloading file was selected mid-write.
Common situations: Selecting a model file while the browser/downloader is still writing it; logs or datasets that grow after selection; editors saving in place; a sync client (Dropbox/OneDrive) replacing placeholder files with real content after selection.
Related errors
- Linked folder changed after it was selected
- Linked source is not a regular file
- Native folder grant has no stable identity.
- Native path is no longer a regular file.
- Native path is no longer a directory.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/e7b9058176a29aec.
Report an issue: GitHub.