siyuan-note/siyuan · warning

Obsidian source file changed

Error message

Obsidian source file changed

What it means

A sentinel error returned when a Vault source file's size or modification time changes between the initial scan and a re-read, indicating the file was edited during analysis/import. readStableObsidianFile stats the file before and after reading; if size or mtime differ, it wraps this sentinel with 'during analysis' or 'while reading'. newObsidianReadUserError maps it to i18n key 346. This is a consistency guard: SiYuan needs the file to be stable to build accurate link/block-ID indices.

Source

Thrown at kernel/model/import_obsidian.go:235

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 {
				active.Cancel()

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Close Obsidian and pause any cloud-sync clients operating on the Vault before starting analysis.
  2. Re-run startObsidianVaultAnalysis after the Vault is quiescent — the fresh scan re-snapshots file metadata.
  3. Copy the Vault to a stable local directory and import the copy instead of the live Vault.
  4. If recurring, exclude the Vault from backup/antivirus scanning during import.

Example fix

// before: Obsidian auto-saving during import triggers mtime change
// readStableObsidianFile -> errObsidianSourceChanged

// after: copy vault to a quiet location first
cp -r /live/Vault /tmp/VaultCopy
// then POST startObsidianVaultAnalysis with localPath=/tmp/VaultCopy
Defensive patterns

Strategy: validation

Validate before calling

// Check no file changed between two stat snapshots (proxy for stability)
func vaultIsStable(vaultDir string, snapshot map[string]fs.FileInfo) (bool, error) {
    for rel, old := range snapshot {
        cur, err := os.Stat(filepath.Join(vaultDir, rel))
        if err != nil { return false, err }
        if cur.Size() != old.Size() || !cur.ModTime().Equal(old.ModTime()) {
            return false, nil
        }
    }
    return true, nil
}

Try / catch

if err := analyzeVault(ctx, localPath); err != nil {
    if errors.Is(err, errObsidianSourceChanged) {
        // advise the user to pause sync/Obsidian and retry
        return errors.New("Vault files changed during analysis; close Obsidian and sync, then retry")
    }
}

Prevention

When it happens

Trigger: During analyzeObsidianVault or importObsidianVaultTask, readStableObsidianFile (line 926) or validateObsidianSourceMetadata (line 1860) detects that a file's Size or ModTime changed between the scan snapshot and the read. Happens if Obsidian or another editor is actively saving notes into the Vault while import is running.

Common situations: Obsidian is left open and auto-saving while SiYuan imports the Vault; a cloud-sync client (Dropbox, OneDrive, iCloud) is writing files into the Vault mid-import; a user edits notes during a long analysis; antivirus or backup tools touch file metadata.

Related errors


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