Skip to content

[Bug]: Gateway never loads externally-installed npm plugins (installed-plugin load stage skipped) — version/layout/clean-rebuild independent #93219

Description

@cxdnicole

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

After the 2026-06-05 runtime migration (nvm node + nvm-installed openclaw → Homebrew node@22 + brew-prefix openclaw, third-party plugin relocated to the projects/<hash>/ self-contained layout), the gateway only loads the 8 bundled stock plugins and never loads any externally-installed npm plugin.

A third-party channel plugin @tencent-weixin/[email protected] (plugin id openclaw-weixin) that loaded fine before the migration stopped loading. The WeChat client shows "暂无法链接openclaw" because the channel never starts; openclaw channels login --channel openclaw-weixin succeeds on the WeChat side ("✅ already connected") but ends with invalid channels.start channel.

This reproduces on 2026.5.28, 2026.6.1, and 2026.6.6 (latest), and survives a complete clean reinstall — so it is not the #90007 migration bug alone (that sqlite migration is fixed in 2026.6.6; this is a separate, deeper defect).

Expected

Gateway loads bundled plugins plus enabled externally-installed plugins from the installed-plugin index, e.g. http server listening (9 plugins: ..., openclaw-weixin, ...) (as it did on 2026-05-26).

Actual

[gateway] http server listening (8 plugins: bonjour, browser, canvas, device-pair,
  file-transfer, memory-core, phone-control, talk-voice; 0.9s)

openclaw-weixin never appears. openclaw channels list → "no configured chat channels".

Environment

  • OS: macOS 15.6 (arm64)
  • Node: Homebrew node@22 v22.22.3 (/opt/homebrew/opt/node@22/bin/node)
  • OpenClaw: npm install -g into /opt/homebrew prefix; reproduced on 2026.5.28 / 2026.6.1 / 2026.6.6
  • Gateway: LaunchAgent ai.openclaw.gateway, gateway.mode = local, port 18789
  • Home: ~/.openclaw

Key evidence: index is correct, but the load stage never runs

After a clean install, ~/.openclaw/state/openclaw.sqlite table installed_plugin_index has 1 row that correctly contains the plugin:

  • host_contract_version = 2026.6.6 (matches running host)
  • compat_registry_version matches resolveCompatRegistryVersion()
  • install_records_json includes openclaw-weixin
  • plugins_json (96 entries) includes a full openclaw-weixin entry (origin: "global", enabled: true, correct source/rootDir/manifestPath)

Yet at OPENCLAW_LOG_LEVEL=trace the gateway logs only the 8 dist/extensions/ bundled loads then loaded 8 plugin(s) (8 attempted). There is not a single log line about projects / installed / discovered / external plugins. The code path that reads installed_plugin_index (loadInstalledPluginIndexInstallRecordsSync) and turns its records into load candidates is never reached.

The plugin module itself is healthy: node --input-type=module -e "import('.../openclaw-weixin/dist/index.js')" → OK; peerDependency openclaw (>=2026.3.22) is satisfied and symlinked to the brew install.

Reproduction

  1. Pre-migration (2026.5.x, plugin in flat ~/.openclaw/npm/node_modules): gateway loads N+1 plugins including the external one.
  2. Migrate runtime to brew node@22 + brew openclaw; plugin ends up in ~/.openclaw/npm/projects/<hash>/.
  3. Gateway now loads only the N bundled plugins.
  4. Confirm installed_plugin_index contains the external plugin with matching host_contract/compat versions.
  5. OPENCLAW_LOG_LEVEL=trace shows the installed-plugin load stage never executes.

Independence from version / layout / state (ruled out)

  • Versions: 2026.5.28, 2026.6.1, 2026.6.6 → all 8 plugins.
  • Layouts: projects/<hash>/, flat ~/.openclaw/npm/node_modules/@scope/name, symlink into dist/extensions/<name> → all 8 plugins.
  • plugins.allow: unset → 8; ["openclaw-weixin"]0 (bundled also dropped); ["<8 bundled ids>","openclaw-weixin"] → 8 (weixin still never attempted).
  • Config: openclaw.json has no plugins.allow/plugins.deny/disable flags — only plugins.entries.{openclaw-weixin,xiaomi}.enabled=true.

Full clean rebuild — still fails

  1. Stop gateway; DELETE FROM installed_plugin_index / plugin_state_entries / plugin_blob_entries / plugin_binding_approvals.
  2. rm -rf ~/.openclaw/npm ~/.openclaw/plugins.
  3. npm rm -g openclaw (removed 285 pkgs) → npm install -g [email protected].
  4. openclaw plugins install @tencent-weixin/[email protected]; enable; daemon install --force; start.

→ gateway still 8 plugins; index re-populated correctly with weixin; trace still shows the installed-plugin load stage never runs.

Workarounds tried — all ineffective

plugins registry --refresh (does not persist a usable installs.json), reinstall plugin, daemon install --force, doctor --repair/--fix, plugins.allow (all combinations), manually writing a valid current-host installs.json, restoring *.migrated files to original names (re-archived on every boot), placing the plugin in all three layouts, full clean reinstall.

Suspected root cause

A gating condition in the gateway plugin loader (this env: macOS arm64 + Homebrew node@22 + ~/.openclaw home) causes the installed-plugin discovery → candidate stage to be skipped entirely, so installed_plugin_index entries are never converted into load candidates. plugins.allow only filters the bundled-extension candidate set; non-bundled plugins are never added to it under any configuration.

Steps to reproduce

  1. Pre-migration (2026.5.x, plugin in flat ~/.openclaw/npm/node_modules): gateway loads N+1 plugins including the external one.
  2. Migrate runtime to brew node@22 + brew openclaw; plugin ends up in ~/.openclaw/npm/projects/<hash>/.
  3. Gateway now loads only the N bundled plugins.
  4. Confirm installed_plugin_index contains the external plugin with matching host_contract/compat versions.
  5. OPENCLAW_LOG_LEVEL=trace shows the installed-plugin load stage never executes.

Expected behavior

Gateway loads bundled plugins plus enabled externally-installed plugins from the installed-plugin index, e.g. http server listening (9 plugins: ..., openclaw-weixin, ...) (as it did on 2026-05-26).

Actual behavior

[gateway] http server listening (8 plugins: bonjour, browser, canvas, device-pair,
  file-transfer, memory-core, phone-control, talk-voice; 0.9s)

openclaw-weixin never appears. openclaw channels list → "no configured chat channels".

OpenClaw version

OpenClaw: npm install -g into /opt/homebrew prefix; reproduced on 2026.5.28 / 2026.6.1 / 2026.6.6

Operating system

OS: macOS 15.6 (arm64)

Install method

Node: Homebrew node@22 v22.22.3 (/opt/homebrew/opt/node@22/bin/node)

Model

Gateway: LaunchAgent ai.openclaw.gateway, gateway.mode = local, port 18789

Provider / routing chain

openclaw->local->gpt

Additional provider/model setup details

  • OS: macOS 15.6 (arm64)
  • Node: Homebrew node@22 v22.22.3 (/opt/homebrew/opt/node@22/bin/node)
  • OpenClaw: npm install -g into /opt/homebrew prefix; reproduced on 2026.5.28 / 2026.6.1 / 2026.6.6
  • Gateway: LaunchAgent ai.openclaw.gateway, gateway.mode = local, port 18789
  • Home: ~/.openclaw

Logs, screenshots, and evidence

After a clean install, `~/.openclaw/state/openclaw.sqlite` table `installed_plugin_index` has 1 row that correctly contains the plugin:
- `host_contract_version = 2026.6.6` (matches running host)
- `compat_registry_version` matches `resolveCompatRegistryVersion()`
- `install_records_json` includes `openclaw-weixin`
- `plugins_json` (96 entries) includes a full `openclaw-weixin` entry (`origin: "global"`, `enabled: true`, correct `source`/`rootDir`/`manifestPath`)

Yet at `OPENCLAW_LOG_LEVEL=trace` the gateway logs **only** the 8 `dist/extensions/` bundled loads then `loaded 8 plugin(s) (8 attempted)`. **There is not a single log line about projects / installed / discovered / external plugins.** The code path that reads `installed_plugin_index` (`loadInstalledPluginIndexInstallRecordsSync`) and turns its records into load candidates is never reached.

The plugin module itself is healthy: `node --input-type=module -e "import('.../openclaw-weixin/dist/index.js')"` → OK; peerDependency `openclaw` (`>=2026.3.22`) is satisfied and symlinked to the brew install.

Impact and severity

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.bugSomething isn't workingclawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.no-staleExclude from stale automationregressionBehavior that previously worked and now fails

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions