{"record":{"id":"1a973007f6691b51","repo":"unslothai/unsloth","slug":"native-path-grant-issue-time-is-invalid","errorCode":null,"errorMessage":"Native path grant issue time is invalid.","messagePattern":"Native path grant issue time is invalid\\.","errorType":"validation","errorClass":"NativePathLeaseError","httpStatus":400,"severity":"error","filePath":"studio/backend/utils/native_path_leases.py","lineNumber":334,"sourceCode":"    )\n    missing = [key for key in required if key not in payload]\n    if missing:\n        raise NativePathLeaseError(\"Native path grant payload is missing required fields.\")\n    if _required_int(payload, \"version\") != 1:\n        raise NativePathLeaseError(\"Native path grant version is unsupported.\")\n    if payload[\"operation\"] != operation:\n        raise NativePathLeaseError(\"Native path grant operation is invalid.\")\n    if expected_kind and payload[\"path_kind\"] != expected_kind:\n        raise NativePathLeaseError(\"Native path grant kind is invalid.\")\n    now_ms = int(time.time() * 1000)\n    issued_at_ms = _required_int(payload, \"issued_at_ms\")\n    expires_at_ms = _required_int(payload, \"expires_at_ms\")\n    if issued_at_ms >= expires_at_ms:\n        raise NativePathLeaseError(\"Native path grant timestamps are inconsistent.\")\n    if expires_at_ms <= now_ms:\n        raise NativePathLeaseError(\"Native path grant has expired.\")\n    if issued_at_ms > now_ms + 30_000:\n        raise NativePathLeaseError(\"Native path grant issue time is invalid.\")\n    for key in (\"canonical_path\", \"nonce\", \"token_id_hash\", \"display_label\"):\n        raw = payload.get(key)\n        if raw is None:\n            continue\n        if \"\\x00\" in str(raw):\n            raise NativePathLeaseError(\"Native path grant contains invalid characters.\")\n\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\":","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/native_path_leases.py#L316-L352","documentation":"The grant's issued_at_ms is more than 30 seconds in the future relative to the backend clock, which the backend treats as an invalid issue time. This 30-second window is a deliberately small allowed clock-skew tolerance; anything beyond it suggests clock drift, a replay of a grant minted elsewhere, or a fabricated payload. The backend rejects future-dated grants to prevent extending a lease's effective lifetime via a fast clock.","triggerScenarios":"verify_native_path_lease() with issued_at_ms > now_ms + 30_000. Happens when the machine/process that signed the grant runs more than 30s ahead (manual clock set, VM resume, dual-boot RTC state), or when a grant string is reused from an environment with a different clock.","commonSituations":"Windows/Linux dual-boot leaving the RTC in local vs UTC mode (~hours of skew); a VM or WSL guest whose clock drifted after host sleep; NTP not yet converged on a freshly booted machine; testing with a grant fixture generated on another machine.","solutions":["Measure skew: compare date +%s%3N in the Tauri shell (or host) vs the backend process environment.","Resync clocks (enable NTP, restart the VM/WSL guest, or fix RTC to UTC in dual-boot setups), then request a fresh grant.","If skew is structural (e.g. sandboxed backend), ensure both signer and verifier derive time from the same host clock.","Regenerate the grant after the clock is fixed; the existing one stays rejected until it falls inside the 30s window (i.e. effectively re-issue)."],"exampleFix":"# before: diagnose\n# host clock 14:02, backend (WSL) clock 14:05 -> 3min skew, grant issued_at is 'future'\n\n# after: resync and re-issue\nsudo hwclock -s            # or restart WSL: wsl --shutdown\nwsl --shutdown && wsl      # guest re-reads host clock\n# then re-pick the file to mint a fresh grant","handlingStrategy":"retry","validationCode":"import base64, json, time\n\ndef issue_time_plausible(lease: str, tolerance_ms: int = 30_000) -> bool:\n    payload = json.loads(base64.urlsafe_b64decode(lease.split('.')[0] + '=='))\n    return int(payload['issued_at_ms']) <= int(time.time() * 1000) + tolerance_ms","typeGuard":null,"tryCatchPattern":"try:\n    grant = verify_native_path_lease(lease, operation='read')\nexcept NativePathLeaseError as exc:\n    if 'issue time is invalid' in str(exc):\n        raise RuntimeError('Clock skew detected between signer and backend; sync clocks and retry') from exc\n    raise","preventionTips":["Run the Tauri signer and Python backend on the same host clock; avoid VM/WSL guests with stale clocks.","Enable NTP; after host sleep/resume, restart clock-dependent guests.","Treat issue-time failures as a clock problem first — retrying without fixing time just burns grants."],"tags":["native-path-lease","clock-skew","validation","desktop"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}