siyuan-note/siyuan · warning

Obsidian Vault has no readable Markdown

Error message

Obsidian Vault has no readable Markdown

What it means

A sentinel error returned by planObsidianDocuments when the Vault contains zero importable Markdown files after scanning. Even though the Vault root and .obsidian config are valid, if no .md files survive the scan (all skipped as hidden, special, or non-importable), planning aborts. The obsidianVaultErrorLanguage helper maps it to i18n key 340.

Source

Thrown at kernel/model/import_obsidian.go:234

}

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()
				return nil, errors.New(Conf.Language(329))
			}
			if active.Cancel != nil {

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Ensure the Vault contains at least one non-hidden .md file that is a regular file (not a symlink).
  2. Rename dotfile notes (starting with .) so they are not skipped by the hidden-file filter.
  3. Replace symlinked notes with real files or copy their content into the Vault directly.
  4. Open the Vault in Obsidian and confirm notes appear in the file explorer before importing.

Example fix

// before: vault only has .hidden-note.md (skipped as hidden)
// planObsidianDocuments -> errObsidianVaultMarkdownMissing

// after: add or rename a regular .md file
mv .hidden-note.md visible-note.md
Defensive patterns

Strategy: validation

Validate before calling

// Count importable Markdown files before calling analysis
func countImportableMarkdown(vaultDir string) (int, error) {
    count := 0
    err := filepath.WalkDir(vaultDir, func(p string, d fs.DirEntry, err error) error {
        if err != nil { return err }
        if d.IsDir() || strings.HasPrefix(d.Name(), ".") { return nil }
        if strings.EqualFold(filepath.Ext(p), ".md") { count++ }
        return nil
    })
    return count, err
}

Try / catch

if _, err := model.StartObsidianVaultAnalysis(localPath); err != nil {
    if errors.Is(err, errObsidianVaultMarkdownMissing) {
        return errors.New("the Vault contains no importable Markdown notes; add or unhide .md files")
    }
}

Prevention

When it happens

Trigger: startObsidianVaultAnalysis succeeds at the root-validation stage, but scanObsidianVaultFiles finds no files ending in .md with an importable mode, so len(mdFiles) == 0 in planObsidianDocuments (line 707-708). Common when all Markdown files are dotfiles, symlinked, or filtered out by isObsidianImportableFileMode.

Common situations: A Vault where every note is hidden (prefixed with .); all .md files are symlinks (skipped via SkippedLinkCount); the Vault only contains non-Markdown attachments; a freshly created Vault with no notes yet; files with modes isObsidianImportableFileMode rejects.

Related errors


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