{"record":{"id":"6ffe76876f1b349c","repo":"siyuan-note/siyuan","slug":"read-vault-directory-s-w","errorCode":null,"errorMessage":"read Vault directory [%s]: %w","messagePattern":"read Vault directory \\[(.+?)\\]: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/import_obsidian.go","lineNumber":603,"sourceCode":"\tif statErr != nil {\n\t\tif os.IsNotExist(statErr) {\n\t\t\treturn \"\", errObsidianVaultConfigMissing\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"%w: read Vault config directory: %v\", errObsidianVaultUnreadable, statErr)\n\t}\n\tif !configInfo.IsDir() || configInfo.Mode()&os.ModeSymlink != 0 || isObsidianResolvedLink(configPath) {\n\t\treturn \"\", errObsidianVaultConfigMissing\n\t}\n\treturn abs, nil\n}\n\nfunc scanObsidianVaultFiles(ctx context.Context, vault *obsidianVaultContext, relDir, absDir string) error {\n\tif err := ctx.Err(); err != nil {\n\t\treturn err\n\t}\n\tentries, err := os.ReadDir(absDir)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read Vault directory [%s]: %w\", relDir, err)\n\t}\n\tsort.Slice(entries, func(i, j int) bool { return strings.ToLower(entries[i].Name()) < strings.ToLower(entries[j].Name()) })\n\tfor _, entry := range entries {\n\t\tif err = ctx.Err(); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tname := entry.Name()\n\t\trel := path.Join(relDir, filepath.ToSlash(name))\n\t\tabs := filepath.Join(absDir, name)\n\t\tif strings.HasPrefix(name, \".\") {\n\t\t\tif relDir == \"\" && name == \".obsidian\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvault.Analysis.SkippedHiddenCount++\n\t\t\tcontinue\n\t\t}\n\t\tentryInfo, infoErr := entry.Info()\n\t\tif infoErr != nil {","sourceCodeStart":585,"sourceCodeEnd":621,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/import_obsidian.go#L585-L621","documentation":"os.ReadDir on a directory inside the Vault failed while scanning Vault files, so the import analysis aborts. The message carries the vault-relative directory and the wrapped OS error so the user can see which directory could not be listed.","triggerScenarios":"scanObsidianVaultFiles calls os.ReadDir(absDir) and the directory exists in the walk (was listed by its parent) but cannot be opened: EACCES, the entry is a special/non-directory file that claimed to be a dir, or the directory disappeared between parent listing and ReadDir.","commonSituations":"Permission differences between directories in the same vault; the vault is on a removable/network drive that dropped out mid-scan; antivirus or sync tools (OneDrive/Dropbox placeholders) interfering; files being deleted while importing.","solutions":["Grant the SiYuan process read/execute permission on the reported subdirectory","Ensure the vault is on a stable local disk, not a removable or paused cloud-sync mount","Close tools that may delete/move vault directories during the import and retry","Check the wrapped OS error in the message (e.g. 'permission denied' vs 'no such file') to target the fix"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const fs = require('fs');\nfor (const dir of allVaultSubdirs) fs.accessSync(dir, fs.constants.R_OK | fs.constants.X_OK);","typeGuard":null,"tryCatchPattern":"try {\n  await importObsidianVault(vaultPath);\n} catch (e) {\n  const m = /read Vault directory \\[([^\\]]+)\\]/.exec(e.message);\n  if (m) console.error('Fix access to', m[1]);\n}","preventionTips":["Keep the vault on a stable local filesystem, not a removable or paused cloud-sync mount","Grant recursive read/execute permission on the vault before import","Don't delete or move vault folders while an import is running"],"tags":["obsidian-import","filesystem","directory-scan","permissions"],"backgroundTag":"directory-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"}