siyuan-note/siyuan · error

initialize fsnotify watcher: %w

Error message

initialize fsnotify watcher: %w

What it means

Returned by addStorageWatch when fsnotify.NewWatcher() fails while lazily initializing the file watcher on first watch. The OS-level inotify/kqueue/ReadDirectoryChangesW error is wrapped. Once it fails p.watcher stays nil so a later Add is not attempted on a bad watcher.

Source

Thrown at kernel/plugin/plugin.go:780

	}
}

// addStorageWatch adds a path to the fsnotify watcher to watch for storage file/directory changes.
func (p *KernelPlugin) addStorageWatch(path string) (err error) {
	if !isPluginFileWatchSupported() {
		return errPluginFileWatchUnsupported
	}

	p.watcherMu.Lock()
	defer p.watcherMu.Unlock()

	if contextErr := p.context.Err(); contextErr != nil {
		return fmt.Errorf("plugin stopped: %w", contextErr)
	}
	if p.watcher == nil {
		p.watcher, err = fsnotify.NewWatcher()
		if err != nil {
			return fmt.Errorf("initialize fsnotify watcher: %w", err)
		}
		p.watcherDone = make(chan struct{})
		go p.startStorageWatch(p.watcher, p.watcherDone)
	}

	err = p.watcher.Add(path)
	return
}

// removeStorageWatch removes a path from the fsnotify watcher to stop watching for storage file/directory changes.
func (p *KernelPlugin) removeStorageWatch(path string) (err error) {
	if !isPluginFileWatchSupported() {
		return errPluginFileWatchUnsupported
	}

	p.watcherMu.Lock()
	defer p.watcherMu.Unlock()

View on GitHub (pinned to 251596fc0d)

Solutions

  1. On Linux raise fs.inotify.max_user_watches (sysctl) and fs.file-max, then retry the watch.
  2. Reduce the number/depth of watched directories; watch specific files instead of trees.
  3. Run SiYuan on a platform with fsnotify support; on mobile this path returns errPluginFileWatchUnsupported instead.
  4. Check the kernel log for the matching ENOMEM/ENOSPC from inotify_add_watch.

Example fix

# before (host default inotify limit)
# plugin call fails with 'initialize fsnotify watcher: ...'

# after (raise inotify watch limit)
sudo sysctl fs.inotify.max_user_watches=524288
sudo sysctl fs.inotify.max_user_instances=512
Defensive patterns

Strategy: try-catch

Validate before calling

// host-level: ensure fs.inotify.max_user_watches is high enough
// (no runtime guard from plugin JS; check platform limits before adding watches)

Try / catch

try { await siyuan.storage.watcher.add(path); } catch (e) { if (/fsnotify|inotify/i.test(String(e))) { console.warn('watch unsupported, polling fallback', e); /* fall back to polling */ } else throw e; }

Prevention

When it happens

Trigger: Calling siyuan.storage.watcher.add(path) for the first time on a system that is out of inotify watches/watches, has too many open file descriptors, or lacks kernel inotify support.

Common situations: Linux hosts with fs.inotify.max_user_watches set too low for many plugins/files, containers with a restricted procfs, or embedded/mobile builds where fsnotify is unavailable.

Related errors


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