NousResearch/hermes-agent · error · Error
Not a directory: ${watchDir}
Error message
Not a directory: ${watchDir} What it means
Thrown by watchDirectory, the fs.watch-based watcher that replaced the disk-plugin door's 5s readdir poll. It requires the target to be an existing directory — fs.existsSync is false, or statSync shows a non-directory (a file was passed). Used for the plugins directory churn signal; the renderer reconciles on watcher ticks.
Source
Thrown at apps/desktop/electron/main.ts:4964
return true
}
function closePreviewWatchers() {
for (const id of previewWatchers.keys()) {
stopPreviewFileWatch(id)
}
}
/** Watch a DIRECTORY for entry churn (folders appearing/vanishing) — the
* disk-plugin door's "new plugin folder" signal, replacing the renderer's 5s
* readdir poll. Same registry + change channel as the preview file watchers
* (the renderer reconciles on any tick; per-file edits stay on their own
* watches), so stopPreviewFileWatch/closePreviewWatchers manage these too. */
function watchDirectory(rawDir) {
const watchDir = path.resolve(String(rawDir || ''))
if (!fs.existsSync(watchDir) || !fs.statSync(watchDir).isDirectory()) {
throw new Error(`Not a directory: ${watchDir}`)
}
const id = crypto.randomBytes(12).toString('base64url')
let timer = null
const watcher = fs.watch(watchDir, () => {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
timer = null
sendPreviewFileChanged({ id, path: watchDir, url: pathToFileURL(watchDir).toString() })
}, PREVIEW_WATCH_DEBOUNCE_MS)
})
previewWatchers.set(id, {
close: () => {View on GitHub (pinned to c896c09c42)
Solutions
- Create the directory first: fs.mkdirSync(watchDir, { recursive: true }) before starting the watch.
- Pass the plugins directory path, not a file inside it.
- Re-request the watch when the directory is (re)created instead of caching a failure.
Example fix
// before
watchDirectory(pluginDir) // throws if dir absent
// after
if (!fs.existsSync(pluginDir)) fs.mkdirSync(pluginDir, { recursive: true })
watchDirectory(pluginDir) Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs')
function ensureWatchableDir(dir) {
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
return fs.statSync(dir).isDirectory()
} Type guard
function isExistingDirectory(p) {
try {
return fs.statSync(p).isDirectory()
} catch {
return false
}
} Prevention
- mkdir -p the plugins dir before watching
- Handle ENOENT from fs.watch after the dir vanishes
- Re-request the watch when the directory is recreated
When it happens
Trigger: IPC watch request for a plugins directory that doesn't exist yet (fresh install, plugins never created); the path points at a file; the directory was deleted between the renderer listing it and the watch call.
Common situations: First run before ~/.hermes/plugins is created; a plugins folder removed while the disk-plugin door was open; passing a file path by mistake.
Related errors
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/8825db8f16ab1ff0.
Report an issue: GitHub.