{"record":{"id":"d0d53ace6659c0fd","repo":"unslothai/unsloth","slug":"native-path-grant-has-the-wrong-path-type","errorCode":null,"errorMessage":"Native path grant has the wrong path type.","messagePattern":"Native path grant has the wrong path type\\.","errorType":"validation","errorClass":"NativePathLeaseError","httpStatus":400,"severity":"error","filePath":"studio/backend/utils/native_path_leases.py","lineNumber":218,"sourceCode":"\n    identity_options = _identity_options(payload)\n    grant = NativePathGrant(\n        operation = str(payload[\"operation\"]),\n        canonical_path = resolved,\n        path_kind = str(payload[\"path_kind\"]),\n        path_type = str(payload[\"path_type\"]),\n        source_kind = str(payload[\"source_kind\"]),\n        token_id_hash = str(payload[\"token_id_hash\"]),\n        display_label = str(payload.get(\"display_label\") or resolved.name),\n        expires_at_ms = _required_int(payload, \"expires_at_ms\"),\n        size_bytes = _optional_int(payload.get(\"size_bytes\")),\n        modified_ms = _optional_int(payload.get(\"modified_ms\")),\n        device_id = identity_options[0][0] if identity_options else None,\n        file_id = identity_options[0][1] if identity_options else None,\n    )\n\n    if expected_path_type and grant.path_type != expected_path_type:\n        raise NativePathLeaseError(\"Native path grant has the wrong path type.\")\n    suffixes = tuple(s.lower() for s in (allowed_suffixes or ()))\n    if suffixes and resolved.suffix.lower() not in suffixes:\n        raise NativePathLeaseError(\"Native path grant has an unsupported file type.\")\n\n    current_identity = _validate_current_stat(grant, identity_options)\n    if current_identity is not None:\n        grant = replace(grant, device_id = current_identity[0], file_id = current_identity[1])\n    _consume_nonce(str(payload[\"nonce\"]), grant.expires_at_ms)\n    _remember_native_path_for_redaction(str(resolved), grant.display_label)\n    return grant\n\n\ndef display_label_for_native_path(value: str | None) -> str | None:\n    if not value:\n        return value\n    with _REDACTION_LOCK:\n        return _NATIVE_PATH_LABELS.get(value, value)\n","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/native_path_leases.py#L200-L236","documentation":"The caller passed expected_path_type to verify_native_path_lease() and the grant's embedded path_type ('file' or 'directory') doesn't match it. Each API endpoint admits only one shape of grant — a file-upload endpoint requires a 'file' grant, a folder-picking endpoint a 'directory' grant — so this blocks replaying a grant against the wrong kind of operation.","triggerScenarios":"Calling an endpoint with a directory-selection grant where a file grant is required (or vice versa); frontend reusing a stored lease from a different picker dialog; passing expected_path_type=\"file\" while the user picked a folder in a directory-mode dialog.","commonSituations":"Shared lease state in the frontend where multiple pickers write to the same variable; copy-pasted call sites where the picker mode (file vs directory) doesn't match the API's expected_path_type; UI regressions that open the wrong dialog variant for the action.","solutions":["Make the picker mode match the endpoint: open the file dialog for endpoints expecting path_type='file', the directory dialog for 'directory'.","Store leases per-purpose in the frontend instead of one shared variable so a directory grant can't be sent to a file endpoint.","After the dialog returns, sanity-check the grant's semantics (which dialog produced it) before enabling the submit action.","If writing a new endpoint, pass expected_path_type explicitly so mismatches fail loudly."],"exampleFix":"# before\nverify_native_path_lease(lease, operation=\"import_weights\", expected_path_type=\"file\")  # lease came from directory picker\n\n# after\nlease = await native_dialog.pick_file(dialog=\"gguf\")  # file picker, not folder picker\nverify_native_path_lease(lease, operation=\"import_weights\", expected_path_type=\"file\")","handlingStrategy":"validation","validationCode":"# Client-side: only enable the file action when the grant came from the file dialog\nassert dialog_mode == \"file\" before submitting to an endpoint documented as file-type.","typeGuard":null,"tryCatchPattern":"try:\n    grant = verify_native_path_lease(lease, operation=OP, expected_path_type=\"file\")\nexcept NativePathLeaseError as exc:\n    if \"wrong path type\" in str(exc):\n        return error_response(400, \"This action needs a single file, not a folder.\")\n    raise","preventionTips":["Key stored leases by picker mode so file/folder grants never cross.","Always pass expected_path_type at new call sites to fail fast.","Mirror backend path_type expectations in the dialog configuration."],"tags":["validation","file-picker","api-contract"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}