siyuan-note/siyuan · error
: selected Vault path is sensitive (wrapped: Obsidian Vault…
Error message
%w: selected Vault path is sensitive (wrapped: Obsidian Vault path is unsafe)
What it means
validateObsidianVaultRoot wraps errObsidianVaultUnsafePath with 'selected Vault path is sensitive' when util.IsSensitivePath(abs) matches — the chosen path is a system-critical location SiYuan refuses to touch (e.g. root, /etc, /usr, Windows system dirs). This protects users from importing from or writing near OS infrastructure.
Solutions
- Choose the actual Obsidian vault folder (one containing a .obsidian directory), not a drive/system root
- Fix the code or config that resolves to the sensitive path (log the abs path to inspect it)
- Move the vault to a normal user directory such as Documents and select that
Example fix
// before
analyzeVault({ localPath: '/' }); // sensitive
// after
analyzeVault({ localPath: '/home/user/Documents/MyVault' }); Defensive patterns
Strategy: validation
Validate before calling
const real = await fs.promises.realpath(vaultPath);
if (isSensitiveSystemPath(real)) throw new Error('Choose the vault folder, not a system directory');
if (!fs.existsSync(path.join(real, '.obsidian'))) warn('Folder does not look like an Obsidian vault'); Try / catch
try { await analyzeVault(opts); } catch (e) { if (isVaultUnsafe(e) && /sensitive/.test(String(e))) showFolderPickerAgain(); else throw e; } Prevention
- Always pick the vault folder through the folder picker, never type drive roots
- Verify the folder contains a .obsidian subfolder before importing
- Log the resolved absolute path to catch resolution bugs that collapse to system roots
When it happens
Trigger: Calling the analyze/import API with localPath pointing at a sensitive system directory such as '/', '/etc', 'C:\Windows', or the user's home root, depending on IsSensitivePath rules.
Common situations: Misconfigured automation defaulting to '/'; user mistakenly picking a drive root in the folder dialog; a bug in path resolution that collapses the path to a system root.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Argon2id Iterations too low (minimum 3)
- asset path escapes data directory
- asset path escapes data directory
- export path is outside export directory
- history path [ ] is not in workspace
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/02fe3a14048bc9f9.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/import_obsidian.go:577
if strings.TrimSpace(localPath) == "" {
return "", fmt.Errorf("%w: path is empty", errObsidianVaultUnreadable)
}
abs, err := filepath.Abs(filepath.Clean(localPath))
if err != nil {
return "", fmt.Errorf("%w: normalize Vault path: %v", errObsidianVaultUnreadable, err)
}
info, err := os.Lstat(abs)
if err != nil {
return "", fmt.Errorf("%w: read Vault root: %v", errObsidianVaultUnreadable, err)
}
if !info.IsDir() {
return "", errObsidianVaultNotDirectory
}
if info.Mode()&os.ModeSymlink != 0 || isObsidianResolvedLink(abs) {
return "", fmt.Errorf("%w: Vault root is a symbolic link or reparse point", errObsidianVaultUnsafePath)
}
if util.IsSensitivePath(abs) {
return "", fmt.Errorf("%w: selected Vault path is sensitive", errObsidianVaultUnsafePath)
}
workspace, _ := filepath.Abs(filepath.Clean(util.WorkspaceDir))
if sameObsidianPath(abs, workspace) || gulu.File.IsSubPath(workspace, abs) || gulu.File.IsSubPath(abs, workspace) {
return "", fmt.Errorf("%w: Vault root and SiYuan workspace contain each other", errObsidianVaultUnsafePath)
}
configPath := filepath.Join(abs, ".obsidian")
configInfo, statErr := os.Lstat(configPath)
if statErr != nil {
if os.IsNotExist(statErr) {
return "", errObsidianVaultConfigMissing
}
return "", fmt.Errorf("%w: read Vault config directory: %v", errObsidianVaultUnreadable, statErr)
}
if !configInfo.IsDir() || configInfo.Mode()&os.ModeSymlink != 0 || isObsidianResolvedLink(configPath) {
return "", errObsidianVaultConfigMissing
}
return abs, nil
}View on GitHub (pinned to 9f775e8a12)