{"record":{"id":"284309edc85e9685","repo":"HKUDS/DeepTutor","slug":"path-rel-r-escapes-the-vault","errorCode":null,"errorMessage":"Path {rel!r} escapes the vault.","messagePattern":"Path (.+?) escapes the vault\\.","errorType":"validation","errorClass":"VaultError","httpStatus":null,"severity":"error","filePath":"deeptutor/capabilities/obsidian/vault.py","lineNumber":93,"sourceCode":"    than letting ``UnicodeDecodeError`` escape) is what makes the refusal\n    legible: the tool layer turns it into a message naming the note and the\n    fix, instead of an opaque failure.\n    \"\"\"\n    try:\n        return path.read_text(encoding=\"utf-8\")\n    except UnicodeDecodeError as exc:\n        raise VaultError(\n            f\"Note {path.name!r} is not valid UTF-8 (byte offset {exc.start}); \"\n            \"editing it would corrupt the undecodable bytes. Fix its encoding first.\"\n        ) from exc\n\n\ndef _safe_join(root: Path, rel: str) -> Path:\n    \"\"\"Resolve ``rel`` under ``root``, refusing anything that escapes the vault.\"\"\"\n    root_resolved = root.resolve()\n    candidate = (root_resolved / rel.lstrip(\"/\")).resolve()\n    if candidate != root_resolved and root_resolved not in candidate.parents:\n        raise VaultError(f\"Path {rel!r} escapes the vault.\")\n    return candidate\n\n\ndef _with_md_suffix(rel: str) -> str:\n    return rel if rel.lower().endswith(\".md\") else f\"{rel}.md\"\n\n\ndef resolve_note(root: Path, ref: str) -> Path | None:\n    \"\"\"Resolve a note reference to a file path the way Obsidian links do.\n\n    ``ref`` may be a vault-relative path (``folder/Note.md``) or a bare note\n    name (``Note``) matched by basename anywhere in the vault. Returns ``None``\n    when nothing matches.\n    \"\"\"\n    ref = (ref or \"\").strip().split(\"#\", 1)[0].split(\"|\", 1)[0].strip()\n    if not ref:\n        return None\n    # Explicit path (has a separator or .md suffix) → resolve directly.","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/capabilities/obsidian/vault.py#L75-L111","documentation":"Error \"Path {rel!r} escapes the vault.\" thrown in HKUDS/DeepTutor.","triggerScenarios":"Thrown at deeptutor/capabilities/obsidian/vault.py:93 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":[],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}