{"record":{"id":"bdb2a30406d18f91","repo":"siyuan-note/siyuan","slug":"initialize-fsnotify-watcher-w","errorCode":null,"errorMessage":"initialize fsnotify watcher: %w","messagePattern":"initialize fsnotify watcher: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/plugin/plugin.go","lineNumber":781,"sourceCode":"\t}\n}\n\n// addStorageWatch adds a path to the fsnotify watcher to watch for storage file/directory changes.\nfunc (p *KernelPlugin) addStorageWatch(path string) (err error) {\n\tif !isPluginFileWatchSupported() {\n\t\treturn errPluginFileWatchUnsupported\n\t}\n\n\tp.watcherMu.Lock()\n\tdefer p.watcherMu.Unlock()\n\n\tif contextErr := p.context.Err(); contextErr != nil {\n\t\treturn fmt.Errorf(\"plugin stopped: %w\", contextErr)\n\t}\n\tif p.watcher == nil {\n\t\tp.watcher, err = fsnotify.NewWatcher()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"initialize fsnotify watcher: %w\", err)\n\t\t}\n\t\tp.watcherDone = make(chan struct{})\n\t\tgo p.startStorageWatch(p.watcher, p.watcherDone)\n\t}\n\n\terr = p.watcher.Add(path)\n\treturn\n}\n\n// removeStorageWatch removes a path from the fsnotify watcher to stop watching for storage file/directory changes.\nfunc (p *KernelPlugin) removeStorageWatch(path string) (err error) {\n\tif !isPluginFileWatchSupported() {\n\t\treturn errPluginFileWatchUnsupported\n\t}\n\n\tp.watcherMu.Lock()\n\tdefer p.watcherMu.Unlock()\n","sourceCodeStart":763,"sourceCodeEnd":799,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/plugin/plugin.go#L763-L799","documentation":"addStorageWatch lazily creates the plugin's fsnotify watcher. If fsnotify.NewWatcher() fails (e.g. the platform lacks inotify support or the OS exhausted watch resources), the error is wrapped as 'initialize fsnotify watcher: <cause>'.","triggerScenarios":"First storage-watch registration on a plugin when no watcher exists yet and the OS cannot create one: inotify instances/watch descriptors exhausted (Linux), unsupported platform (mobile builds disable file watching), or resource limits.","commonSituations":"Linux systems with low fs.inotify.max_user_instances/max_user_watches; containers with restricted inotify; mobile kernels where watching is disabled; watching very large directory trees exhausting descriptors.","solutions":["Raise fs.inotify.max_user_instances and fs.inotify.max_user_watches (sysctl) on Linux","Reduce the number of watched paths (watch fewer directories, use recursive logic sparingly)","On mobile/unsupported platforms, avoid file-watch APIs and use polling or explicit refresh instead","Check the wrapped cause to confirm resource exhaustion vs platform limitation"],"exampleFix":"// before\nawait plugin.addStorageWatch(largeDir);\n\n// after\ntry {\n  await plugin.addStorageWatch(largeDir);\n} catch (e) {\n  console.warn(\"watch unavailable, falling back to polling:\", String(e));\n}\n","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await plugin.addStorageWatch(path);\n} catch (e) {\n  if (String(e).includes(\"initialize fsnotify watcher\")) {\n    startPollingFallback(path); // poll mtime instead of fsnotify\n  } else throw e;\n}","preventionTips":["On Linux, keep fs.inotify.max_user_instances/watches high enough","Limit the number of concurrently watched paths","On mobile/unsupported platforms use polling instead of file watches"],"tags":["fsnotify","watcher","inotify","platform"],"backgroundTag":"missing-dependency","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}