Summary
shouldIgnoreScannedDirectory() in src/plugins/discovery.ts only skips .bak/.backup-/.disabled directories. It does not skip node_modules, .git, .venv, browser_data, or any other heavy dependency/build directories.
When a workspace skill or plugin contains node_modules, the plugin discovery scanner descends into every subdirectory and probes for package manifests via openBoundaryFileSync. This exhausts the process file descriptor table on macOS and causes spawn EBADF (errno -9) on all subsequent exec tool calls.
The skills watcher (DEFAULT_SKILLS_WATCH_IGNORED in refresh.ts) and memory watcher (IGNORED_MEMORY_WATCH_DIR_NAMES in manager-sync-ops.ts) already ignore these directories — but the plugin discovery scanner does not.
Environment
- OpenClaw: 2026.3.11 (29dc654) — latest release
- OS: macOS (Darwin, arm64)
- Node.js: v22.22.1
Steps to Reproduce
- Install a skill/plugin that has its own
node_modules (e.g. memory-lancedb-pro with ~5,000 files in node_modules/)
- Start the gateway:
openclaw gateway start
- Check FD count:
lsof -p $(pgrep openclaw-gateway) | wc -l
- Observe 12,000+ open file descriptors, mostly REG (regular file) in read-only mode
- Attempt any
exec tool call → fails with spawn EBADF
Expected Behavior
Plugin discovery should skip node_modules, .git, .venv, and other directories that cannot contain valid plugins. FD count should stay in the hundreds, not thousands.
Actual Behavior
$ lsof -p $(pgrep openclaw-gateway) | wc -l
12232
$ lsof -p $(pgrep openclaw-gateway) | awk '{print $NF}' | grep node_modules | wc -l
8595
All exec calls fail with spawn EBADF.
Root Cause
src/plugins/discovery.ts, function shouldIgnoreScannedDirectory():
function shouldIgnoreScannedDirectory(dirName: string): boolean {
const normalized = dirName.trim().toLowerCase();
if (!normalized) return true;
if (normalized.endsWith(".bak")) return true; // ← only these
if (normalized.includes(".backup-")) return true; // ← three
if (normalized.includes(".disabled")) return true; // ← patterns
return false;
}
This function is called by discoverInDirectory() which recurses into every subdirectory of plugin roots. Without node_modules in the skip list, it enters dependency trees with thousands of packages.
Compare with the skills watcher (DEFAULT_SKILLS_WATCH_IGNORED) which already ignores node_modules, .git, dist, .venv, venv, __pycache__, .mypy_cache, .pytest_cache, build, .cache.
Workaround
Manually delete node_modules from workspace skills and restart the gateway. FD count drops from 12,232 to 1,231.
Previously
Summary
shouldIgnoreScannedDirectory()insrc/plugins/discovery.tsonly skips.bak/.backup-/.disableddirectories. It does not skipnode_modules,.git,.venv,browser_data, or any other heavy dependency/build directories.When a workspace skill or plugin contains
node_modules, the plugin discovery scanner descends into every subdirectory and probes for package manifests viaopenBoundaryFileSync. This exhausts the process file descriptor table on macOS and causesspawn EBADF(errno -9) on all subsequentexectool calls.The skills watcher (
DEFAULT_SKILLS_WATCH_IGNOREDinrefresh.ts) and memory watcher (IGNORED_MEMORY_WATCH_DIR_NAMESinmanager-sync-ops.ts) already ignore these directories — but the plugin discovery scanner does not.Environment
Steps to Reproduce
node_modules(e.g.memory-lancedb-prowith ~5,000 files innode_modules/)openclaw gateway startlsof -p $(pgrep openclaw-gateway) | wc -lexectool call → fails withspawn EBADFExpected Behavior
Plugin discovery should skip
node_modules,.git,.venv, and other directories that cannot contain valid plugins. FD count should stay in the hundreds, not thousands.Actual Behavior
All
execcalls fail withspawn EBADF.Root Cause
src/plugins/discovery.ts, functionshouldIgnoreScannedDirectory():This function is called by
discoverInDirectory()which recurses into every subdirectory of plugin roots. Withoutnode_modulesin the skip list, it enters dependency trees with thousands of packages.Compare with the skills watcher (
DEFAULT_SKILLS_WATCH_IGNORED) which already ignoresnode_modules,.git,dist,.venv,venv,__pycache__,.mypy_cache,.pytest_cache,build,.cache.Workaround
Manually delete
node_modulesfrom workspace skills and restart the gateway. FD count drops from 12,232 to 1,231.Previously
spawn EBADFerror on all exec tool calls** #2532 — originalspawn EBADFtracking issue