{"record":{"id":"504737b4b2c8a206","repo":"unslothai/unsloth","slug":"native-path-grant-has-an-unsupported-path-type","errorCode":null,"errorMessage":"Native path grant has an unsupported path type.","messagePattern":"Native path grant has an unsupported path type\\.","errorType":"validation","errorClass":"NativePathLeaseError","httpStatus":400,"severity":"error","filePath":"studio/backend/utils/native_path_leases.py","lineNumber":359,"sourceCode":"\n\ndef _validate_current_stat(\n    grant: NativePathGrant, identity_options: tuple[tuple[int, int], ...]\n) -> tuple[int, int] | None:\n    try:\n        st = os.lstat(grant.canonical_path)\n    except OSError as exc:\n        raise NativePathLeaseError(\"Native path is no longer accessible.\") from exc\n    if _stat_module.S_ISLNK(st.st_mode):\n        raise NativePathLeaseError(\"Native path is no longer a regular file.\")\n    if grant.path_type == \"file\":\n        if not _stat_module.S_ISREG(st.st_mode):\n            raise NativePathLeaseError(\"Native path is no longer a regular file.\")\n    elif grant.path_type == \"directory\":\n        if not _stat_module.S_ISDIR(st.st_mode):\n            raise NativePathLeaseError(\"Native path is no longer a directory.\")\n    else:\n        raise NativePathLeaseError(\"Native path grant has an unsupported path type.\")\n\n    if grant.size_bytes is not None and st.st_size != grant.size_bytes:\n        raise NativePathLeaseError(\"Native path changed after it was selected.\")\n    current_modified_ms = int(st.st_mtime_ns // 1_000_000)\n    if grant.modified_ms is not None and current_modified_ms != grant.modified_ms:\n        raise NativePathLeaseError(\"Native path changed after it was selected.\")\n    if grant.path_kind == \"document-folder\" and not identity_options:\n        raise NativePathLeaseError(\"Native path grant is missing its folder identity.\")\n    current_identity = (st.st_dev, st.st_ino)\n    expected_identity = _runtime_identity(identity_options)\n    if expected_identity is not None and current_identity != expected_identity:\n        raise NativePathLeaseError(\"Native path changed after it was selected.\")\n    return current_identity if expected_identity is not None else None\n\n\ndef _consume_nonce(nonce: str, expires_at_ms: int) -> None:\n    now_ms = int(time.time() * 1000)\n    with _REPLAY_LOCK:","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/native_path_leases.py#L341-L377","documentation":"The signed payload's path_type is neither \"file\" nor \"directory\", so the backend does not know how to validate the on-disk object. This is a signer/backend contract violation: verify_native_path_lease() only understands grants for files and directories. It indicates the Rust signer emitted an unknown path_type value or the backend is older than the signer.","triggerScenarios":"verify_native_path_lease() with payload['path_type'] not in {'file','directory'}: a new signer version introduced 'symlink' or 'drive' types; a test payload hand-built with a wrong string; version mismatch after a partial desktop-app update.","commonSituations":"Desktop app updated the Rust shell but not the Python backend (or vice versa); custom forks adding new path kinds without updating this validator; fuzz/corpus testing with arbitrary path_type strings.","solutions":["Decode the grant payload and read its path_type value to see what the signer emitted.","Update the Python backend (studio) and the Tauri desktop shell together so both agree on the path_type vocabulary.","If you maintain the signer, restrict path_type to 'file' or 'directory' until the backend supports more kinds.","Re-select the path after updating to obtain a grant with a supported type."],"exampleFix":"// before (Rust signer)\n\"path_type\": if is_symlink { \"symlink\" } else { \"file\" }, // unsupported value\n\n// after\n\"path_type\": \"file\", // only 'file' | 'directory' are valid","handlingStrategy":"type-guard","validationCode":"import base64, json\n\nSUPPORTED_PATH_TYPES = {'file', 'directory'}\n\ndef grant_path_type_supported(lease: str) -> bool:\n    payload = json.loads(base64.urlsafe_b64decode(lease.split('.')[0] + '=='))\n    return payload.get('path_type') in SUPPORTED_PATH_TYPES","typeGuard":"SUPPORTED_PATH_TYPES = {'file', 'directory'}\n\ndef is_supported_path_type(value: object) -> bool:\n    return isinstance(value, str) and value in SUPPORTED_PATH_TYPES","tryCatchPattern":"try:\n    grant = verify_native_path_lease(lease, operation='read')\nexcept NativePathLeaseError as exc:\n    if 'unsupported path type' in str(exc):\n        return respond(400, 'Desktop app and backend versions differ; update both and re-select.')\n    raise","preventionTips":["Ship the Rust signer and Python backend as one atomic desktop update.","Pin the path_type vocabulary ('file'|'directory') in a shared constant both sides import or duplicate.","Log the offending path_type value when this fires to identify the version skew."],"tags":["native-path-lease","version-mismatch","contract","validation"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}