openclaw - ✅(Solved) Fix 4.22: Discord provider crash-loops with 'Cannot find package openclaw' on npm global install (ESM subpath import fails from plugin-runtime-deps cache) [2 pull requests, 3 comments, 3 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#70756Fetched 2026-04-24 05:53:58
View on GitHub
Comments
3
Participants
3
Timeline
13
Reactions
0
Author
Timeline (top)
cross-referenced ×5referenced ×4commented ×3closed ×1

On a clean npm install -g [email protected], every Discord provider instance crash-loops immediately after plugin provisioning with:

[discord] [default] channel exited: Cannot find package 'openclaw' imported from
/home/<user>/.openclaw-<profile>/plugin-runtime-deps/openclaw-2026.4.22-<hash>/dist/extensions/discord/provider-<hash>.js
[discord] [default] auto-restart attempt N/10 in 300s

Gateway HTTP (/health) stays alive because only the Discord provider dies, but Discord messaging is completely broken fleet-wide. Affects 20/20 gateways in my deployment.

Root Cause

The Discord provider at plugin-runtime-deps/openclaw-2026.4.22-<hash>/dist/extensions/discord/provider-<hash>.js does bare-specifier subpath imports:

import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
import { chunkItems, logDebug, ... } from "openclaw/plugin-sdk/text-runtime";
import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
// ... ~15 more 'openclaw/plugin-sdk/*' imports

The provider's own node_modules sibling directory (plugin-runtime-deps/openclaw-<hash>/node_modules/) is populated with every OTHER peer (acpx, @anthropic-ai, discord-api-types, @buape/carbon, etc.) — but openclaw itself is missing from it:

$ ls /home/openclaw/.openclaw-<profile>/plugin-runtime-deps/openclaw-2026.4.22-<hash>/node_modules/
accepts  acpx  agent-base  @agentclientprotocol  ajv  ajv-formats  ansi-regex  ...
# no `openclaw` directory here

Node's ESM resolver walks up from the provider file looking for node_modules/openclaw. It doesn't find it locally, and (because npm prefix is /usr) it doesn't reach the global /usr/lib/node_modules/openclaw either — user home is traversed but /usr is not an ancestor. The resolver gives up and throws.

The package exports declaration is valid:

$ jq '.exports | keys | map(select(test("plugin-sdk")))' /usr/lib/node_modules/openclaw/package.json
["./plugin-sdk", "./plugin-sdk/account-core", "./plugin-sdk/account-helpers", "./plugin-sdk/account-id", ...]

So subpath resolution would work if openclaw were findable. It just isn't findable from the plugin cache location.

Fix Action

Fix / Workaround

Workaround (local patch, NOT a real fix)

This blocks all Discord I/O on any 4.22 install where npm prefix is /usr (the standard npm global location on Debian/Ubuntu when using apt-managed Node or a system install). Gateway HTTP endpoints stay up but the bot can neither send nor receive messages, so the Discord-integrated fleet workflow is non-functional until the symlink workaround is applied.

Happy to provide more journal output, full dependency listings, or test a patch.

PR fix notes

PR #70770: fix: materialize openclaw package root in staged plugin runtime deps

Description (problem / solution / changelog)

Problem

Providers running from ~/.openclaw/plugin-runtime-deps/<hash>/ fail to resolve bare-specifier imports like import { ... } from "openclaw/plugin-sdk/..." because the staging flow copies transitive deps into a fresh node_modules/ but omits the host openclaw package itself.

At runtime, when the provider executes, jiti's resolveLoaderPluginSdkPackageRoot walks up looking for a package.json with name="openclaw" and fails without this materialized root.

Fix

Materialize a minimal openclaw package root in the staged node_modules/openclaw/ directory during stageInstalledRootRuntimeDeps, including:

  • package.json (needed for exports resolution and name="openclaw" detection)
  • dist/plugin-sdk/ (compiled SDK modules for subpath exports)

This is much lighter than copying the entire dist/ directory — only the plugin-sdk subpath exports that providers actually import are materialized.

Fixes #70756

Changed files

  • scripts/stage-bundled-plugin-runtime-deps.mjs (modified, +22/-0)
  • test/scripts/stage-bundled-plugin-runtime-deps.test.ts (modified, +68/-0)

PR #70852: fix(plugins): stage bundled-plugin runtime-dep install outside the plugin root

Description (problem / solution / changelog)

Summary

Fixes gateway-startup plugin-runtime-dep install failure on packaged (Docker image, npm global) installs of 2026.4.22 where every bundled plugin whose package.json still contains a workspace:* dep fails with:

npm error code EUNSUPPORTEDPROTOCOL
npm error Unsupported URL Type "workspace:": workspace:*

Reported in #70844 (Docker image, EUNSUPPORTEDPROTOCOL at install step); same root cause as #70701, #70756, #70773, #70818, #70839 (npm global, downstream Cannot find package 'openclaw' from plugin-runtime-deps/… at ESM import).

Root cause

ensureBundledPluginRuntimeDeps in src/plugins/bundled-runtime-deps.ts already filters workspace: specs from the CLI argument list (normalizeInstallableRuntimeDepVersion, parseInstallableRuntimeDep). But the install step is spawnSync("npm", ["install", ...specs], { cwd: installExecutionRoot }), and installExecutionRoot defaults to installRoot. When installRoot === pluginRoot (the packaged case where the plugin dir is writable and no external stage is configured), npm reads the plugin's own package.json as the project manifest and tries to resolve its workspace:* deps — failing the whole batch regardless of what was passed on the CLI.

Evidence: upstream/main carries workspace:* declarations in 106 extensions/*/package.json (predominantly "@openclaw/plugin-sdk": "workspace:*"). The 18 plugins that fail in the Docker repro are exactly the subset that declare such entries as runtime deps (dependencies / optionalDependencies).

The npm-global variants in #70701 / #70756 / #70773 / #70818 / #70839 hit a related but different surface: resolveBundledRuntimeDependencyInstallRoot resolves to an external stage dir (clean manifest), so npm install succeeds but the resulting node_modules/ tree does not satisfy the filtered-out workspace packages, and the subsequent ESM import of openclaw fails at plugin load. Same defect class, different failure point.

Fix

Activate the existing isolated-execution-root + replaceNodeModulesDir machinery for the packaged case too. When installRoot === pluginRoot and we are not in the source-checkout cache-dir path, stage the install inside <installRoot>/.openclaw-install-stage (minimal generated package.json) and move the produced node_modules/ back to the plugin root as before.

+const isPluginRootInstall =
+  path.resolve(installRoot) === path.resolve(params.pluginRoot);
+const sourceCheckoutCacheStage =
+  cacheDir &&
+  isPluginRootInstall &&
+  resolveSourceCheckoutBundledPluginPackageRoot(params.pluginRoot)
+    ? cacheDir
+    : undefined;
 const installExecutionRoot =
-  cacheDir &&
-  path.resolve(installRoot) === path.resolve(params.pluginRoot) &&
-  resolveSourceCheckoutBundledPluginPackageRoot(params.pluginRoot)
-    ? cacheDir
-    : undefined;
+  sourceCheckoutCacheStage ??
+  (isPluginRootInstall ? path.join(installRoot, PLUGIN_ROOT_INSTALL_STAGE_DIR) : undefined);

No change to the existing workspace: filter, no new surface, no change to external stage or source-checkout semantics.

Shape note

@steipete flagged in #70138 that runtime-dep repair belongs at gateway/plugin startup (not npm pack postinstall). This change keeps that contract — it only widens when the existing stage/move is activated; the repair still runs through ensureBundledPluginRuntimeDeps called from src/plugins/loader.ts:2190. It does not reintroduce the eager-install shape that was closed in #70650.

Validation

  • pnpm exec vitest run --config test/vitest/vitest.plugins.config.ts src/plugins/bundled-runtime-deps.test.ts — 31/31 (includes 1 new regression test: stages plugin-root install when the plugin's own package.json declares workspace:* deps)
  • pnpm exec vitest run --config test/vitest/vitest.plugins.config.ts src/plugins/ — 43/43 across 8 test files
  • pnpm exec tsgo --noEmit -p tsconfig.core.json — clean
  • pnpm exec tsgo --noEmit -p tsconfig.core.test.json — clean
  • pnpm exec oxlint src/plugins/bundled-runtime-deps.ts src/plugins/bundled-runtime-deps.test.ts — 0 warnings, 0 errors
  • node scripts/check-src-extension-import-boundary.mjs --json[]
  • node scripts/check-sdk-package-extension-import-boundary.mjs --json[]

I did not run codex review --base origin/main because I do not have Codex CLI access locally; happy to run Codex review in a later iteration if a maintainer provides guidance.

Test plan

  • Build ghcr.io/openclaw/openclaw:<this-branch> and verify gateway startup against an existing ~/.openclaw that was pre-populated from 2026.4.15, reproducing the repro in #70844 from a clean state.
  • Smoke: verify <pluginRoot>/node_modules/ is populated after gateway start and the .openclaw-install-stage/ sub-directory is cleaned up / idempotent across restarts.
  • Spot-check that source-checkout dev flow (pnpm dev in the monorepo) still uses the cache-dir stage (not .openclaw-install-stage/) so no regression on contributor ergonomics.
  • Cross-check with reporters on #70701 / #70756 / #70773 / #70818 / #70839 that the downstream Cannot find package 'openclaw' symptom also resolves.

AI assistance

This PR was AI-assisted with Claude Code (Opus 4.7). All code paths changed here were read end-to-end by me; the diagnosis against src/plugins/loader.ts:2190 and src/plugins/bundled-runtime-deps.ts is documented in the linked issue #70844 comment thread.

Testing degree: fully tested for the touched bundled-plugin runtime-dep install-staging surface.

I understand the code path changed here: packaged bundled plugins now stage their runtime-dep install one directory below pluginRoot so npm never reads the plugin's workspace:*-containing manifest during install; the existing replaceNodeModulesDir helper moves the produced node_modules/ back to pluginRoot after install succeeds.

Closes #70844

Changed files

  • CHANGELOG.md (modified, +1/-1)
  • scripts/e2e/bundled-channel-runtime-deps-docker.sh (modified, +2/-1)
  • src/plugins/bundled-runtime-deps.test.ts (modified, +96/-0)
  • src/plugins/bundled-runtime-deps.ts (modified, +69/-34)
  • src/plugins/loader.test.ts (modified, +34/-27)
  • src/plugins/loader.ts (modified, +2/-1)

Code Example

[discord] [default] channel exited: Cannot find package 'openclaw' imported from
/home/<user>/.openclaw-<profile>/plugin-runtime-deps/openclaw-2026.4.22-<hash>/dist/extensions/discord/provider-<hash>.js
[discord] [default] auto-restart attempt N/10 in 300s

---

import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
import { chunkItems, logDebug, ... } from "openclaw/plugin-sdk/text-runtime";
import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
// ... ~15 more 'openclaw/plugin-sdk/*' imports

---

$ ls /home/openclaw/.openclaw-<profile>/plugin-runtime-deps/openclaw-2026.4.22-<hash>/node_modules/
accepts  acpx  agent-base  @agentclientprotocol  ajv  ajv-formats  ansi-regex  ...
# no `openclaw` directory here

---

$ jq '.exports | keys | map(select(test("plugin-sdk")))' /usr/lib/node_modules/openclaw/package.json
["./plugin-sdk", "./plugin-sdk/account-core", "./plugin-sdk/account-helpers", "./plugin-sdk/account-id", ...]

---

mkdir -p ~/node_modules
ln -sfn /usr/lib/node_modules/openclaw ~/node_modules/openclaw
systemctl --user restart openclaw-gateway-<profile>
RAW_BUFFERClick to expand / collapse

Summary

On a clean npm install -g [email protected], every Discord provider instance crash-loops immediately after plugin provisioning with:

[discord] [default] channel exited: Cannot find package 'openclaw' imported from
/home/<user>/.openclaw-<profile>/plugin-runtime-deps/openclaw-2026.4.22-<hash>/dist/extensions/discord/provider-<hash>.js
[discord] [default] auto-restart attempt N/10 in 300s

Gateway HTTP (/health) stays alive because only the Discord provider dies, but Discord messaging is completely broken fleet-wide. Affects 20/20 gateways in my deployment.

Environment

  • OpenClaw: 2026.4.22 (commit 00bd2cf)
  • Install: sudo npm install -g [email protected]
  • npm prefix: /usr (so package is at /usr/lib/node_modules/openclaw)
  • Node: v22.22.0
  • OS: Ubuntu 24.04.4 LTS, kernel 6.8.0
  • Previous version 2026.4.15 on the same machines did not exhibit this.

Root cause

The Discord provider at plugin-runtime-deps/openclaw-2026.4.22-<hash>/dist/extensions/discord/provider-<hash>.js does bare-specifier subpath imports:

import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
import { chunkItems, logDebug, ... } from "openclaw/plugin-sdk/text-runtime";
import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
// ... ~15 more 'openclaw/plugin-sdk/*' imports

The provider's own node_modules sibling directory (plugin-runtime-deps/openclaw-<hash>/node_modules/) is populated with every OTHER peer (acpx, @anthropic-ai, discord-api-types, @buape/carbon, etc.) — but openclaw itself is missing from it:

$ ls /home/openclaw/.openclaw-<profile>/plugin-runtime-deps/openclaw-2026.4.22-<hash>/node_modules/
accepts  acpx  agent-base  @agentclientprotocol  ajv  ajv-formats  ansi-regex  ...
# no `openclaw` directory here

Node's ESM resolver walks up from the provider file looking for node_modules/openclaw. It doesn't find it locally, and (because npm prefix is /usr) it doesn't reach the global /usr/lib/node_modules/openclaw either — user home is traversed but /usr is not an ancestor. The resolver gives up and throws.

The package exports declaration is valid:

$ jq '.exports | keys | map(select(test("plugin-sdk")))' /usr/lib/node_modules/openclaw/package.json
["./plugin-sdk", "./plugin-sdk/account-core", "./plugin-sdk/account-helpers", "./plugin-sdk/account-id", ...]

So subpath resolution would work if openclaw were findable. It just isn't findable from the plugin cache location.

Repro

  1. Fresh Ubuntu 24, Node 22.
  2. sudo npm install -g [email protected].
  3. Create a profile with Discord configured, start the gateway.
  4. First-boot plugin provisioning creates ~/.openclaw-<profile>/plugin-runtime-deps/openclaw-2026.4.22-<hash>/.
  5. Observe [discord] channel exited: Cannot find package 'openclaw' in journalctl, followed by auto-restart attempt N/10.

Workaround (local patch, NOT a real fix)

mkdir -p ~/node_modules
ln -sfn /usr/lib/node_modules/openclaw ~/node_modules/openclaw
systemctl --user restart openclaw-gateway-<profile>

This puts openclaw on the Node ESM walk-up path (user home). Works because the resolver does reach ~/node_modules from ~/.openclaw-*/plugin-runtime-deps/.... Confirmed restart produces [gateway] ready (5 plugins: acpx, browser, discord, lobster, memory-core; ~9s) with zero further Cannot find package errors.

I can cleanly reproduce the bug by removing the symlink and restarting; it crash-loops again within one provisioning cycle.

Suggested fix

One of:

  1. Include openclaw itself in the plugin-runtime-deps/openclaw-<hash>/node_modules/ bundle during plugin provisioning (simplest, matches how other peers are handled).
  2. Or: rewrite the provider bundler to convert openclaw/plugin-sdk/* imports to relative paths into the same cache dir, since the subpath exports are stable.
  3. Or: set NODE_PATH automatically in the spawned provider process to include the global install location.

Option 1 seems most aligned with the existing cache strategy.

Impact

This blocks all Discord I/O on any 4.22 install where npm prefix is /usr (the standard npm global location on Debian/Ubuntu when using apt-managed Node or a system install). Gateway HTTP endpoints stay up but the bot can neither send nor receive messages, so the Discord-integrated fleet workflow is non-functional until the symlink workaround is applied.

Happy to provide more journal output, full dependency listings, or test a patch.

extent analysis

TL;DR

The most likely fix is to include openclaw itself in the plugin-runtime-deps/openclaw-<hash>/node_modules/ bundle during plugin provisioning.

Guidance

  • Verify that the openclaw package is not present in the plugin-runtime-deps/openclaw-<hash>/node_modules/ directory, which is causing the Discord provider to crash-loop.
  • Consider implementing one of the suggested fixes, such as including openclaw in the bundle, rewriting the provider bundler, or setting NODE_PATH automatically.
  • Test the workaround by creating a symlink to the global openclaw installation in the user's home directory, as described in the issue.
  • Check the journal output and dependency listings to ensure that the fix is working as expected.

Example

No code snippet is provided, as the issue is related to the packaging and deployment of the openclaw package, rather than a specific code error.

Notes

The issue is specific to the openclaw package version 2026.4.22 and the npm installation with a prefix of /usr. The suggested fixes may have different implications for different environments and use cases.

Recommendation

Apply the suggested fix by including openclaw itself in the plugin-runtime-deps/openclaw-<hash>/node_modules/ bundle during plugin provisioning, as this seems to be the most aligned with the existing cache strategy.

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 - ✅(Solved) Fix 4.22: Discord provider crash-loops with 'Cannot find package openclaw' on npm global install (ESM subpath import fails from plugin-runtime-deps cache) [2 pull requests, 3 comments, 3 participants]