siyuan-note/siyuan · error · obsidianUserError

349

349

Error message

the Markdown file list changed after analysis

What it means

revalidateObsidianVault detects that the set of Markdown files changed between analysis and import: the counts of originalMarkdown and currentMarkdown differ. Reported with code 349 ('The Vault contents changed after analysis; analyze the Vault again'). This is the count-based fast path; the per-key membership check is 789.

Source

Thrown at kernel/model/import_obsidian.go:1821

		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 251596fc0d)

Solutions

  1. Stop all external writes to the vault (close Obsidian, pause sync), then re-run StartObsidianVaultAnalysis to produce a fresh task.
  2. Immediately follow a successful analysis with StartObsidianVaultImport to minimise the window for external mutation.
  3. If the change is intentional (you added notes), simply re-analyse — the new files will be included.
  4. For shared/synced vaults, copy to a stable local directory and import from the copy.

Example fix

// before: edit vault after analysis -> count mismatch -> code 349
//   StartObsidianVaultAnalysis(vault)  // ok
//   <user adds 3 new notes in Obsidian>
//   StartObsidianVaultImport(taskID, nb)  // fails 349

// after: re-analyse after edits stabilise
StartObsidianVaultAnalysis(vault)  // fresh snapshot
StartObsidianVaultImport(newTaskID, nb)
Defensive patterns

Strategy: validation

Validate before calling

// Snapshot the markdown file set; refuse to import if it changed.
func markdownSet(path string) map[string]bool { /* walk, collect .md keys */ }
// atAnalysis := markdownSet(vault)
// if !reflect.DeepEqual(atAnalysis, markdownSet(vault)) { re-analyse }

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Between the analysis task completing and StartObsidianVaultImport running, markdown files were added or removed in the vault (Obsidian sync pulled new notes, user deleted files, a sync conflict resolved). revalidateObsidianVault re-scans and compares counts; a mismatch aborts import.

Common situations: User continued using Obsidian after analysing; iCloud/Dropbox/Git sync delivered new or deleted .md files; vault on a shared volume edited by another machine; long gap between analysis and import (the Ready task has a TTL after which it expires anyway).

Related errors


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