{"record":{"id":"756307b6215d45aa","repo":"unslothai/unsloth","slug":"native-path-grant-payload-is-missing-required-fiel","errorCode":null,"errorMessage":"Native path grant payload is missing required fields.","messagePattern":"Native path grant payload is missing required fields\\.","errorType":"validation","errorClass":"NativePathLeaseError","httpStatus":400,"severity":"error","filePath":"studio/backend/utils/native_path_leases.py","lineNumber":319,"sourceCode":"\ndef _validate_payload(\n    payload: dict[str, Any], *, operation: str, expected_kind: str | None\n) -> None:\n    required = (\n        \"version\",\n        \"operation\",\n        \"canonical_path\",\n        \"path_kind\",\n        \"path_type\",\n        \"source_kind\",\n        \"token_id_hash\",\n        \"issued_at_ms\",\n        \"expires_at_ms\",\n        \"nonce\",\n    )\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:","sourceCodeStart":301,"sourceCodeEnd":337,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/native_path_leases.py#L301-L337","documentation":"The decoded payload object is missing one or more of the required fields: version, operation, canonical_path, path_kind, path_type, source_kind, token_id_hash, issued_at_ms, expires_at_ms, or nonce (also raised by _required_int when a needed field is None). Since the signature verified, this points at a signer that omitted fields — usually a homegrown or outdated signer, not client tampering.","triggerScenarios":"A custom Rust/Python signing harness that doesn't emit every required field; a grant issued by an older app version whose schema lacked a field (e.g. token_id_hash or nonce added later); optional fields like size_bytes/modified_ms are fine to omit, but the ten required ones are not.","commonSituations":"Version skew between an outdated desktop shell and a newer backend; test fixtures built before schema additions; hand-written signers copying an example payload from old docs.","solutions":["Update the desktop app (or your signing harness) to the current grant schema so all ten required fields are present.","If you maintain the signer, diff its payload keys against the required tuple in _validate_payload and emit any missing ones.","Reject/retire grants from old app versions — have users re-pick files after upgrading both shell and backend together."],"exampleFix":"# before (test signer omitting fields)\npayload = {\"version\": 1, \"operation\": op, \"canonical_path\": str(p)}\n\n# after\npayload = {\n    \"version\": 1, \"operation\": op, \"canonical_path\": str(p),\n    \"path_kind\": \"file\", \"path_type\": \"file\", \"source_kind\": \"dialog\",\n    \"token_id_hash\": token_hash, \"issued_at_ms\": now_ms,\n    \"expires_at_ms\": now_ms + 600_000, \"nonce\": secrets.token_hex(16),\n}","handlingStrategy":"validation","validationCode":"REQUIRED = {\"version\",\"operation\",\"canonical_path\",\"path_kind\",\"path_type\",\"source_kind\",\"token_id_hash\",\"issued_at_ms\",\"expires_at_ms\",\"nonce\"}\n\ndef payload_complete(payload: dict) -> bool:\n    return REQUIRED <= payload.keys()","typeGuard":null,"tryCatchPattern":"try:\n    grant = verify_native_path_lease(lease, operation=OP)\nexcept NativePathLeaseError as exc:\n    if \"missing required fields\" in str(exc):\n        return error_response(400, \"File grant is incomplete; update the app and re-select the file.\")\n    raise","preventionTips":["Upgrade shell and backend together so grant schema stays in sync.","Pin signer fixtures to the required-field list in _validate_payload.","Add a contract test that every field the verifier requires is emitted by the signer."],"tags":["schema","payload","version-skew","signing"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}