siyuan-note/siyuan · error

Obsidian Vault path is unsafe: Vault root and SiYuan workspa

Error message

Obsidian Vault path is unsafe: Vault root and SiYuan workspace contain each other

What it means

A wrapped variant of errObsidianVaultUnsafePath (line 579-581): returned when the Vault root is the same as, a parent of, or a child of the SiYuan workspace directory. The check uses sameObsidianPath and gulu.File.IsSubPath in both directions to prevent recursive or destructive directory relationships. Importing a Vault that overlaps the workspace would cause SiYuan to scan its own data directory, leading to infinite recursion or data corruption. The error wraps the unsafe sentinel with ': Vault root and SiYuan workspace contain each other'.

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 err

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Move the Vault to a directory completely outside the SiYuan workspace tree.
  2. If the workspace was set inside the Vault, change the SiYuan workspace to a different location.
  3. Use a copy of the Vault in a neutral directory (e.g. /tmp or ~/Imports) for import.
  4. Confirm the two paths share no ancestor/descendant relationship before importing.

Example fix

// before: vault is inside the workspace
// workspace = /home/user/SiYuan/data
// vault    = /home/user/SiYuan/data/MyVault
// -> "Obsidian Vault path is unsafe: Vault root and SiYuan workspace contain each other"

// after: vault outside workspace
// vault = /home/user/ObsidianVaults/MyVault
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no overlap between Vault root and workspace
abs, _ := filepath.Abs(filepath.Clean(localPath))
ws, _ := filepath.Abs(filepath.Clean(util.WorkspaceDir))
if abs == ws || gulu.File.IsSubPath(ws, abs) || gulu.File.IsSubPath(abs, ws) {
    return errors.New("Vault path overlaps the SiYuan workspace; choose a separate directory")
}

Try / catch

if _, err := model.StartObsidianVaultAnalysis(localPath); err != nil {
    if errors.Is(err, errObsidianVaultUnsafePath) && strings.Contains(err.Error(), "contain each other") {
        return errors.New("the Vault overlaps the SiYuan workspace; move it to a separate directory")
    }
}

Prevention

When it happens

Trigger: POST /api/import/startObsidianVaultAnalysis where abs == workspace, workspace is under abs (Vault is a parent of workspace), or abs is under workspace (Vault is inside the SiYuan data dir). Any of the three IsSubPath/sameObsidianPath checks at line 580 returns true.

Common situations: User placed the Obsidian Vault inside the SiYuan workspace/data folder; the workspace was set to the Vault's parent; the user confused the two directories and selected the workspace itself as the Vault; a default workspace path happens to contain the Vault.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/f6d36f36c5dd735e. Report an issue: GitHub.