siyuan-note/siyuan · warning
349
349
Error message
the Markdown file list changed after analysis
What it means
Before starting an Obsidian import, the vault is re-scanned (fresh analysis) and its Markdown file set is compared against the set captured at the original analysis. If the counts differ, the importer aborts with localized user error 349: the source vault changed between analysis and import, so proceeding could import inconsistent data.
Solutions
- Re-run the import from scratch so the analysis and import see the same vault state
- Close Obsidian and pause sync clients (iCloud/OneDrive/Syncthing) during the import
- Retry once the vault is stable; the error is intentionally transient by design
Defensive patterns
Strategy: retry
Validate before calling
// before import, take a snapshot hash/count of *.md files and confirm nothing changes for a few seconds
n1 := countMD(vaultDir); time.Sleep(2 * time.Second); n2 := countMD(vaultDir)
if n1 != n2 { /* vault still changing; wait */ } Try / catch
if code == 349 {
// re-run the import; the error is a protective retry-able abort
} Prevention
- Close Obsidian and pause sync clients for the duration of the import
- Do not edit, add, or delete notes between analysis and import confirmation
- Import from a static copy of the vault
When it happens
Trigger: len(originalMarkdown) != len(currentMarkdown) in the pre-import consistency check — a .md file was added to or removed from the vault after the initial analysis pass.
Common situations: Obsidian (or a sync client) was open and syncing while the user clicked import; a background backup tool added files; user edited the vault between the analysis dialog and confirming import.
Related errors
- 346
- 348
- block [ ] is not a sortable document
- created notebook is not mounted
- global attachment [ ] already exists
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/fa6f824d6f605de4.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/import_obsidian.go:1843
Analysis: &ObsidianVaultAnalysis{BlockingErrors: []string{}, Warnings: []string{}},
}
if err := scanObsidianVaultFiles(ctx, fresh, "", vault.Root); err != nil {
return err
}
originalMarkdown := map[string]bool{}
for _, doc := range vault.Docs {
if !doc.Synthetic {
originalMarkdown[obsidianPathKey(doc.Source.RelPath)] = true
}
}
currentMarkdown := map[string]bool{}
for key, file := range fresh.Files {
if file.IsMD {
currentMarkdown[key] = true
}
}
if len(originalMarkdown) != len(currentMarkdown) {
return newObsidianUserError(349, "", errors.New("the Markdown file list changed after analysis"))
}
for key := range originalMarkdown {
if !currentMarkdown[key] {
return newObsidianUserError(349, "", errors.New("the Markdown file list changed after analysis"))
}
}
if len(vault.Assets) != len(fresh.Assets) {
return newObsidianUserError(349, "", errors.New("the attachment file list changed after analysis"))
}
for key := range vault.Assets {
if fresh.Assets[key] == nil {
return newObsidianUserError(349, "", errors.New("the attachment file list changed after analysis"))
}
}
for _, doc := range vault.Docs {
if doc.Synthetic {
continue
}View on GitHub (pinned to 9f775e8a12)