openclaw - 💡(How to fix) Fix [v2026.4.24] doctor --fix installs bundled deps to wrong dir; ENOTEMPTY in plugin-sdk alias crashes node host [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#72380Fetched 2026-04-27 05:30:39
View on GitHub
Comments
1
Participants
2
Timeline
3
Reactions
0
Timeline (top)
closed ×1commented ×1cross-referenced ×1

On a fresh upgrade to OpenClaw 2026.4.24 (npm global install), two distinct regressions in the bundled-plugin-runtime-deps machinery prevent the agent from responding on Telegram (and likely other channels). Both are reproducible and have local workarounds, but they should be fixed upstream.

Error Message

[plugins] telegram failed during register from .../telegram/index.js: Error: ENOTEMPTY, Directory not empty: /Users/.../plugin-runtime-deps/openclaw-2026.4.24-<hash>/dist/extensions/node_modules/openclaw/plugin-sdk [openclaw] CLI failed: PluginLoadFailureError: plugin load failed: telegram at maybeThrowOnPluginLoadError (loader-.js:2712:8) at loadOpenClawPlugins (loader-.js:3588:3) at resolveRuntimePluginRegistry (loader-.js:2443:9) at resolveOrLoadRuntimePluginRegistry (runtime-registry-loader-.js:37:7) at ensurePluginRegistryLoaded (runtime-registry-loader-.js:68:2) at ensureNodeHostPluginRegistry (node-cli-.js:1656:43) at runNodeHost (node-cli-*.js:2189:2)

Root Cause

On a fresh upgrade to OpenClaw 2026.4.24 (npm global install), two distinct regressions in the bundled-plugin-runtime-deps machinery prevent the agent from responding on Telegram (and likely other channels). Both are reproducible and have local workarounds, but they should be fixed upstream.

Fix Action

Workaround

Manually drop a stub at the install root:

echo '{"name":"openclaw-runtime-deps-install","private":true}' \
  > ~/.openclaw/plugin-runtime-deps/openclaw-<version>-<hash>/package.json

Then openclaw doctor --fix works correctly.

Code Example

if (isolatedExecutionRoot) fs.writeFileSync(
    path.join(installExecutionRoot, "package.json"),
    ...{ name: "openclaw-runtime-deps-install", private: true })

---

echo '{"name":"openclaw-runtime-deps-install","private":true}' \
  > ~/.openclaw/plugin-runtime-deps/openclaw-<version>-<hash>/package.json

---

[plugins] telegram failed during register from .../telegram/index.js:
Error: ENOTEMPTY, Directory not empty:
/Users/.../plugin-runtime-deps/openclaw-2026.4.24-<hash>/dist/extensions/node_modules/openclaw/plugin-sdk
[openclaw] CLI failed: PluginLoadFailureError: plugin load failed: telegram
    at maybeThrowOnPluginLoadError (loader-*.js:2712:8)
    at loadOpenClawPlugins         (loader-*.js:3588:3)
    at resolveRuntimePluginRegistry (loader-*.js:2443:9)
    at resolveOrLoadRuntimePluginRegistry (runtime-registry-loader-*.js:37:7)
    at ensurePluginRegistryLoaded         (runtime-registry-loader-*.js:68:2)
    at ensureNodeHostPluginRegistry       (node-cli-*.js:1656:43)
    at runNodeHost                        (node-cli-*.js:2189:2)

---

if (fs.existsSync(pluginSdkAliasDir)
    && !fs.lstatSync(pluginSdkAliasDir).isDirectory())
    fs.rmSync(pluginSdkAliasDir, { recursive: true, force: true });
fs.mkdirSync(pluginSdkAliasDir, { recursive: true });
for (const entry of fs.readdirSync(pluginSdkDir, ...)) {
    ...
    writeRuntimeModuleWrapper(...);
}
RAW_BUFFERClick to expand / collapse

Summary

On a fresh upgrade to OpenClaw 2026.4.24 (npm global install), two distinct regressions in the bundled-plugin-runtime-deps machinery prevent the agent from responding on Telegram (and likely other channels). Both are reproducible and have local workarounds, but they should be fixed upstream.

Environment

  • OpenClaw 2026.4.24 (cbcfdf6), upgraded from 2026.4.21
  • Node v24.13.0 (fnm), npm v11.6.2
  • macOS 25.4.0
  • Single-machine local install, no symlinked node_modules tricks
  • Plugins enabled: telegram, anthropic, google, deepseek, moonshot, brave, open-prose, plus 3 third-party (claude-mem, openclaw-weixin, rules-enforcer)

Bug 1: installBundledRuntimeDeps runs npm install with no package.json, so deps land in $HOME/node_modules

In dist/bundled-runtime-deps-*.js, installBundledRuntimeDeps only writes the stub package.json when installExecutionRoot !== installRoot:

if (isolatedExecutionRoot) fs.writeFileSync(
    path.join(installExecutionRoot, "package.json"),
    ...{ name: "openclaw-runtime-deps-install", private: true })

The default call path from repairBundledRuntimeDepsInstallRoot does not pass a separate execution root, so they're equal, no stub is written, and npm install <33 specs> runs with no package.json in cwd. npm walks up the directory tree, finds $HOME/package.json (in my case declaring an unrelated @fission-ai/openspec), treats $HOME as the project root, and:

  • installs the openclaw bundled deps into $HOME/node_modules
  • on subsequent runs, reifies $HOME/node_modules to match $HOME/package.json, thereby REMOVING the openclaw deps it just installed
  • ~/.openclaw/plugin-runtime-deps/openclaw-<v>-<hash>/ never gets a node_modules directory, so the bundled-deps loader keeps reporting them missing, and doctor --fix runs again, ad infinitum.

In my npm logs the install exits 0 with silly reify moves {} and no added N packages line, confirming npm found nothing to install relative to $HOME/package.json.

Workaround

Manually drop a stub at the install root:

echo '{"name":"openclaw-runtime-deps-install","private":true}' \
  > ~/.openclaw/plugin-runtime-deps/openclaw-<version>-<hash>/package.json

Then openclaw doctor --fix works correctly.

Suggested fix

Always write the stub package.json before invoking npm, regardless of whether installRoot and installExecutionRoot differ.

Bug 2: ENOTEMPTY on dist/extensions/node_modules/openclaw/plugin-sdk crashes the node host (PluginLoadFailureError → agent unresponsive)

After Bug 1 is worked around and bundled deps are properly installed, the gateway starts but the node host crashes during plugin registration:

[plugins] telegram failed during register from .../telegram/index.js:
Error: ENOTEMPTY, Directory not empty:
/Users/.../plugin-runtime-deps/openclaw-2026.4.24-<hash>/dist/extensions/node_modules/openclaw/plugin-sdk
[openclaw] CLI failed: PluginLoadFailureError: plugin load failed: telegram
    at maybeThrowOnPluginLoadError (loader-*.js:2712:8)
    at loadOpenClawPlugins         (loader-*.js:3588:3)
    at resolveRuntimePluginRegistry (loader-*.js:2443:9)
    at resolveOrLoadRuntimePluginRegistry (runtime-registry-loader-*.js:37:7)
    at ensurePluginRegistryLoaded         (runtime-registry-loader-*.js:68:2)
    at ensureNodeHostPluginRegistry       (node-cli-*.js:1656:43)
    at runNodeHost                        (node-cli-*.js:2189:2)

Channel is "loaded" per openclaw plugins list and openclaw health reports Telegram: ok, so the bot polls successfully — but no node host means messages arrive and the agent never responds.

ensureOpenClawPluginSdkAlias in loader-*.js only deletes pluginSdkAliasDir when it's NOT a directory (line ~2190):

if (fs.existsSync(pluginSdkAliasDir)
    && !fs.lstatSync(pluginSdkAliasDir).isDirectory())
    fs.rmSync(pluginSdkAliasDir, { recursive: true, force: true });
fs.mkdirSync(pluginSdkAliasDir, { recursive: true });
for (const entry of fs.readdirSync(pluginSdkDir, ...)) {
    ...
    writeRuntimeModuleWrapper(...);
}

When the alias directory already exists with a previously-populated tree, re-staging hits some intermediate state and fails with ENOTEMPTY. Two plugin-runtime-deps roots (one for v2026.4.24 plus a stale openclaw-unknown-* from earlier installs) both reproduce.

Workaround (verified)

  1. openclaw gateway stop
  2. rm -rf ~/.openclaw/plugin-runtime-deps/openclaw-*/dist/extensions/node_modules/openclaw/plugin-sdk (for every install root present, including any openclaw-unknown-*)
  3. openclaw gateway start

After this, the node host comes up clean, telegram registers, and the agent responds to messages.

Suggested fix

  • Always remove the existing pluginSdkAliasDir (when it IS a directory) before re-staging, OR perform an atomic stage+rename via a temp dir;
  • And/or skip re-staging when the alias contents already match.
  • Bonus: garbage-collect stale openclaw-unknown-* install roots that get left behind when readPackageVersion can't determine a version.

Possibly related

  • #72200 (bundled-deps installer thrash) — different repro but same subsystem
  • #72058 (npm deps missing after 2026.4.24 update)
  • #72114 (bundled runtime deps staging timeout)

extent analysis

TL;DR

The most likely fix involves modifying the installBundledRuntimeDeps function to always write a stub package.json before invoking npm install, and ensuring that the pluginSdkAliasDir is properly removed or updated to prevent ENOTEMPTY errors.

Guidance

  1. Verify the issue: Confirm that the problem occurs when installExecutionRoot equals installRoot, causing npm install to run without a package.json in the current working directory.
  2. Apply the workaround for Bug 1: Manually create a stub package.json at the install root using the provided command to ensure openclaw doctor --fix works correctly.
  3. Investigate Bug 2: Check if the pluginSdkAliasDir exists and is not empty, causing the ENOTEMPTY error during plugin registration.
  4. Apply the workaround for Bug 2: Stop the gateway, remove the existing pluginSdkAliasDir, and restart the gateway to resolve the ENOTEMPTY error.

Example

No code snippet is provided as the issue is more related to the logic and workflow of the installBundledRuntimeDeps and ensureOpenClawPluginSdkAlias functions.

Notes

The suggested fixes involve modifying the installBundledRuntimeDeps function to always write a stub package.json and ensuring that the pluginSdkAliasDir is properly removed or updated. Additionally, garbage-collecting stale openclaw-unknown-* install roots may help prevent similar issues in the future.

Recommendation

Apply the workarounds for both Bug 1 and Bug 2 to resolve the immediate issues, and consider implementing the suggested fixes to prevent similar problems in the future. The reason for this recommendation is that the workarounds provide a temporary solution, while the suggested fixes address the underlying causes of the issues.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [v2026.4.24] doctor --fix installs bundled deps to wrong dir; ENOTEMPTY in plugin-sdk alias crashes node host [1 comments, 2 participants]