siyuan-note/siyuan · error
Obsidian Vault path is not a directory
Error message
Obsidian Vault path is not a directory
What it means
A sentinel error returned when the Vault root path exists but is not a directory (e.g. it is a regular file). It is produced directly in validateObsidianVaultRoot at the `!info.IsDir()` check, without additional wrapping. The obsidianVaultErrorLanguage helper maps it to i18n key 337 for user-facing display.
Source
Thrown at kernel/model/import_obsidian.go:231
func (err *obsidianUserError) Error() string {
return err.Cause.Error()
}
func (err *obsidianUserError) Unwrap() error {
return err.Cause
}
func newObsidianUserError(detailLanguage int, relPath string, cause error) error {
return &obsidianUserError{DetailLanguage: detailLanguage, RelPath: relPath, Cause: cause}
}
var (
obsidianTasksMu sync.Mutex
obsidianTasks = map[string]*obsidianTask{}
obsidianActive string
errObsidianVaultUnreadable = errors.New("Obsidian Vault is unreadable")
errObsidianVaultNotDirectory = errors.New("Obsidian Vault path is not a directory")
errObsidianVaultUnsafePath = errors.New("Obsidian Vault path is unsafe")
errObsidianVaultConfigMissing = errors.New("Obsidian Vault config directory is missing")
errObsidianVaultMarkdownMissing = errors.New("Obsidian Vault has no readable Markdown")
errObsidianSourceChanged = errors.New("Obsidian source file changed")
obsidianBlockIDPattern = regexp.MustCompile(`(?m)(?:^|[ \t])\^([A-Za-z0-9-]+)[ \t]*$`)
obsidianQuotePattern = regexp.MustCompile(`^((?:[ \t]*>[ \t]?)+)(.*)$`)
obsidianListItemPattern = regexp.MustCompile(`^([ \t]*(?:[-+*]|\d+[.)])[ \t]+)(.*)$`)
obsidianFootnotePattern = regexp.MustCompile(`(?m)\[\^[^\]\r\n]+\]`)
)
func StartObsidianVaultAnalysis(localPath string) (*ObsidianVaultTask, error) {
var replacedTaskID string
obsidianTasksMu.Lock()
if obsidianActive != "" {
if active := obsidianTasks[obsidianActive]; active != nil && !isObsidianTerminalState(active.State) {
if !isObsidianPreImportState(active.State) {
obsidianTasksMu.Unlock()View on GitHub (pinned to 251596fc0d)
Solutions
- Point localPath at the Vault root folder (the directory containing the .obsidian subfolder), not at a file inside or outside it.
- If the Vault arrived as a ZIP, extract it to a directory first, then pass that directory's path.
- In the UI file picker, ensure a folder/directory is selected, not an individual file.
Example fix
// before: user passes a file path localPath := "/home/user/MyVault.md" // -> errObsidianVaultNotDirectory // after: pass the directory containing .obsidian localPath := "/home/user/MyVault"
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the path is a directory before calling analysis
func ensureIsDir(p string) error {
info, err := os.Stat(p)
if err != nil { return err }
if !info.IsDir() { return errors.New("path is not a directory") }
return nil
} Try / catch
if _, err := model.StartObsidianVaultAnalysis(localPath); err != nil {
if errors.Is(err, errObsidianVaultNotDirectory) {
return errors.New("please select the Vault folder, not a file")
}
} Prevention
- Restrict the UI folder picker to directory selection only.
- Reject file paths (non-directory) on the client before submitting.
- If importing from an archive, extract it to a folder first.
When it happens
Trigger: POST /api/import/startObsidianVaultAnalysis is called with a localPath that resolves to a file (a .md file, a .zip archive, etc.) rather than a directory. os.Lstat succeeds but info.IsDir() is false.
Common situations: User selects a single Markdown file or a ZIP export instead of the Vault folder in the file picker; a path typo points at a file with the same base name; the Vault was exported as a single archive that has not been unpacked.
Related errors
- Obsidian Vault is unreadable
- Obsidian Vault path is unsafe
- Obsidian Vault config directory is missing
- Obsidian Vault has no readable Markdown
- Obsidian source file changed
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/01657a5e26e18571.
Report an issue: GitHub.