siyuan-note/siyuan · error

read Vault path [%s]: %w

Error message

read Vault path [%s]: %w

What it means

While walking the vault, `entry.Info()` failed for a path and the importer classified the path as essential (a directory, or a `.md` file), so it aborts with this error instead of silently skipping. Non-essential files whose metadata cannot be read are only recorded as analysis warnings. This surfaces filesystem-level problems that would otherwise corrupt the import inventory.

Source

Thrown at kernel/model/import_obsidian.go:623

	sort.Slice(entries, func(i, j int) bool { return strings.ToLower(entries[i].Name()) < strings.ToLower(entries[j].Name()) })
	for _, entry := range entries {
		if err = ctx.Err(); err != nil {
			return err
		}
		name := entry.Name()
		rel := path.Join(relDir, filepath.ToSlash(name))
		abs := filepath.Join(absDir, name)
		if strings.HasPrefix(name, ".") {
			if relDir == "" && name == ".obsidian" {
				continue
			}
			vault.Analysis.SkippedHiddenCount++
			continue
		}
		entryInfo, infoErr := entry.Info()
		if infoErr != nil {
			if entry.IsDir() || strings.EqualFold(filepath.Ext(name), ".md") {
				return fmt.Errorf("read Vault path [%s]: %w", rel, infoErr)
			}
			vault.Analysis.Warnings = append(vault.Analysis.Warnings, rel)
			continue
		}
		if entry.Type()&os.ModeSymlink != 0 || entryInfo.Mode()&os.ModeSymlink != 0 || isObsidianResolvedLink(abs) {
			vault.Analysis.SkippedLinkCount++
			continue
		}
		if entryInfo.IsDir() {
			nestedConfig := filepath.Join(abs, ".obsidian")
			if nestedInfo, nestedErr := os.Lstat(nestedConfig); nestedErr == nil {
				if nestedInfo.IsDir() || nestedInfo.Mode()&os.ModeSymlink != 0 || isObsidianResolvedLink(nestedConfig) {
					vault.Analysis.SkippedNestedVaultCount++
					continue
				}
			}
			if err = scanObsidianVaultFiles(ctx, vault, rel, abs); err != nil {
				return err

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Identify the path from the error message and check it exists with `ls -la <vault>/<rel>`
  2. Fix permissions on that specific file or directory
  3. Pause sync clients (OneDrive/Dropbox/iCloud) during import so files are not changing
  4. Enable long-path support or shorten paths on Windows if MAX_PATH is the cause

Example fix

# before: file metadata unreadable
ls -la vault/notes.md   # permission denied

# after
chmod u+rw vault/notes.md
Defensive patterns

Strategy: try-catch

Validate before calling

import fs from "fs"
try { fs.statSync(mdFilePath) } catch (e) { repairOrRemove(mdFilePath) }

Try / catch

try {
  await importVault(vaultRoot)
} catch (e) {
  if (String(e.message).includes("read Vault path")) {
    const rel = e.message.match(/\[(.*?)\]/)?.[1]
    console.warn(`Metadata unreadable for ${rel}; check existence and permissions`)
  }
}

Prevention

When it happens

Trigger: During scanObsidianVaultFiles, entry.Info() returns an error for a directory entry or for a file whose extension is `.md` (case-insensitive), e.g. permission denied, entry vanished between ReadDir and Info, or long-path errors on Windows.

Common situations: A markdown file deleted or renamed by Obsidian/sync while import is running; permission changes on specific notes; cloud-sync placeholders whose metadata cannot be hydrated (e.g. OneDrive files-on-demand); Windows MAX_PATH overruns.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/2ab8d5557d952793. Report an issue: GitHub.