{"record":{"id":"68bed470ad0c05f4","repo":"siyuan-note/siyuan","slug":"w-read-vault-root-v-wrapped-obsidian-vault-is-unreadable","errorCode":null,"errorMessage":"%w: read Vault root: %v (wrapped: Obsidian Vault is unreadable)","messagePattern":"%w: read Vault root: (.+?) \\(wrapped: Obsidian Vault is unreadable\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/import_obsidian.go","lineNumber":568,"sourceCode":"\tret.Analysis.UnreferencedFileCount = len(ret.ImportAssets) - len(ret.ReferencedAssets)\n\tif ret.Analysis.UnreferencedFileCount < 0 {\n\t\tret.Analysis.UnreferencedFileCount = 0\n\t}\n\tprogress(100, \"Analysis completed\")\n\treturn ret, nil\n}\n\nfunc validateObsidianVaultRoot(localPath string) (string, error) {\n\tif strings.TrimSpace(localPath) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: path is empty\", errObsidianVaultUnreadable)\n\t}\n\tabs, err := filepath.Abs(filepath.Clean(localPath))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: normalize Vault path: %v\", errObsidianVaultUnreadable, err)\n\t}\n\tinfo, err := os.Lstat(abs)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"%w: read Vault root: %v\", errObsidianVaultUnreadable, err)\n\t}\n\tif !info.IsDir() {\n\t\treturn \"\", errObsidianVaultNotDirectory\n\t}\n\tif info.Mode()&os.ModeSymlink != 0 || isObsidianResolvedLink(abs) {\n\t\treturn \"\", fmt.Errorf(\"%w: Vault root is a symbolic link or reparse point\", errObsidianVaultUnsafePath)\n\t}\n\tif util.IsSensitivePath(abs) {\n\t\treturn \"\", fmt.Errorf(\"%w: selected Vault path is sensitive\", errObsidianVaultUnsafePath)\n\t}\n\tworkspace, _ := filepath.Abs(filepath.Clean(util.WorkspaceDir))\n\tif sameObsidianPath(abs, workspace) || gulu.File.IsSubPath(workspace, abs) || gulu.File.IsSubPath(abs, workspace) {\n\t\treturn \"\", fmt.Errorf(\"%w: Vault root and SiYuan workspace contain each other\", errObsidianVaultUnsafePath)\n\t}\n\tconfigPath := filepath.Join(abs, \".obsidian\")\n\tconfigInfo, statErr := os.Lstat(configPath)\n\tif statErr != nil {\n\t\tif os.IsNotExist(statErr) {","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/import_obsidian.go#L550-L586","documentation":"validateObsidianVaultRoot wraps errObsidianVaultUnreadable with 'read Vault root: %v' when os.Lstat(abs) fails — the path does not exist or cannot be stat'ed (permission, IO error). The underlying OS error is included in the message.","triggerScenarios":"Analyzing a vault path that was deleted/renamed, contains a typo, sits on an unmounted drive, or is unreadable due to permissions (including macOS TCC blocking access to folders).","commonSituations":"Vault moved since last use; network drive disconnected; Windows OneDrive folder offline; macOS 'Files and Folders' permission denied for the kernel app.","solutions":["Verify the path exists (ls / dir) and correct typos, then re-run the analysis","Remount the drive/share hosting the vault","Fix permissions: chmod/chown, or grant the app Full Disk/folder access (macOS System Settings)","Pick the vault folder again via the folder picker to store a fresh path"],"exampleFix":"// before\nanalyzeVault({ localPath: '/Volumes/USB/vault' }); // drive unplugged\n// after\nif (fs.existsSync(vaultPath)) {\n  analyzeVault({ localPath: vaultPath });\n}","handlingStrategy":"validation","validationCode":"const st = await fs.promises.stat(vaultPath).catch(() => null);\nif (!st || !st.isDirectory()) throw new Error(`Vault path missing: ${vaultPath}`);","typeGuard":"async function isReadableDir(p) { try { return (await fs.promises.stat(p)).isDirectory(); } catch { return false; } }","tryCatchPattern":"try { await analyzeVault(opts); } catch (e) { if (isVaultUnreadable(e) && /read Vault root/.test(String(e))) { showPathFixUi(opts.localPath); } else throw e; }","preventionTips":["Re-select the vault if it was moved or renamed","Remount network/USB drives before importing","On macOS grant the app Full Disk access; on Windows check ACLs"],"tags":["obsidian","filesystem","path-not-found","permissions"],"backgroundTag":"file-not-found","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}