siyuan-note/siyuan · error · errObsidianVaultUnsafePath
%w: Vault root and SiYuan workspace contain each other
Error message
%w: Vault root and SiYuan workspace contain each other
What it means
During Obsidian vault import validation, SiYuan rejects the selected vault root if it overlaps the SiYuan workspace directory in either direction: identical paths, vault inside workspace, or workspace inside vault. This prevents the importer from recursively reading/altering the workspace's own data, config, and temp files, and from nesting vault content inside the running workspace. The check runs on absolute, cleaned paths using case-normalized subpath comparison.
Source
Thrown at kernel/model/import_obsidian.go:581
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
}
func scanObsidianVaultFiles(ctx context.Context, vault *obsidianVaultContext, relDir, absDir string) error {
if err := ctx.Err(); err != nil {
return errView on GitHub (pinned to 8641553a1f)
Solutions
- Choose a vault root that is neither inside nor an ancestor of the SiYuan workspace directory
- If the notes live inside <workspace>/data, use SiYuan's native workspace flow instead of the Obsidian importer
- Move the Obsidian vault to a sibling directory outside the workspace before importing
- Verify WorkspaceDir (Help - About in the UI) to see which path is conflicting
Example fix
// before: vault inside workspace vaultRoot := filepath.Join(util.WorkspaceDir, "data", "MyVault") err := importObsidian(vaultRoot) // after: vault in an independent location vaultRoot := "/home/user/MyVault" err := importObsidian(vaultRoot)
Defensive patterns
Strategy: validation
Validate before calling
const abs = path.resolve(vaultRoot)
const workspace = path.resolve(getSiYuanWorkspaceDir())
if (abs === workspace || abs.startsWith(workspace + path.sep) || workspace.startsWith(abs + path.sep)) {
throw new Error("Vault root and SiYuan workspace overlap; choose a different vault root")
} Type guard
function isPathInside(child, parent) {
const rel = path.relative(path.resolve(parent), path.resolve(child))
return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel)
} Prevention
- Keep Obsidian vaults in a dedicated directory separate from the SiYuan workspace
- Never select the home directory or Documents as a vault root when the workspace lives nearby
- Before importing, resolve both paths with filepath.Abs and check containment
When it happens
Trigger: Calling the Obsidian import flow with a vault root that equals util.WorkspaceDir, is a parent of it (e.g. selecting the user home directory that contains the workspace folder), or is nested inside the workspace (e.g. selecting <workspace>/data or a notes folder already inside the workspace).
Common situations: User picks 'home' or 'Documents' as the vault when SiYuan workspace lives under it; user created Obsidian vault inside <workspace>/data previously; confusing workspace with data directory; running SiYuan portable with workspace next to vaults.
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
- %w: read Vault config directory: %v
- read Vault directory [%s]: %w
- read Vault path [%s]: %w
- Vault paths differ only by letter case [%s] and [%s]
- 346
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/45bbcf754091fa2d.
Report an issue: GitHub.