Skip to content

openclaw status eagerly loads disabled channel plugins, crashing when bundled plugin deps aren't installed #70338

Description

@dineshmistry

Summary

openclaw status fails at startup with Cannot find module '@larksuiteoapi/node-sdk' (and then cascades to nostr-tools, etc.) even when those channels are marked disabled in openclaw plugins list. Other commands (openclaw health, openclaw doctor --fix) run cleanly against the same install.

Environment

  • openclaw --version2026.4.21 (f788c88)
  • Install: npm install -g openclaw/Users/dinesh/.npm-global/lib/node_modules/openclaw
  • macOS 25.3.0, Node from npm-global prefix
  • Enabled channels: Telegram only

Reproduction

  1. npm install -g openclaw (fresh global install, do not set OPENCLAW_EAGER_BUNDLED_PLUGIN_DEPS=1)
  2. Configure a single channel (e.g. Telegram)
  3. openclaw status

Expected

Status renders channel health for enabled channels. Disabled bundled plugins are not loaded.

Actual

[openclaw] Failed to start CLI: Error: Cannot find module '@larksuiteoapi/node-sdk'
Require stack:
- /…/openclaw/dist/extensions/feishu/client-yWGpoGkZ.js

After installing that dep manually, status advances and crashes on the next bundled extension (nostr-tools for the nostr plugin), and so on.

Stack (abbreviated)

loadBundledEntryModuleSync (channel-entry-contract-*.js:148)
loadChannelPlugin (channel-entry-contract-*.js:162)
getBundledChannelPluginForRoot (bundled-*.js:348)
iterateBootstrapChannelPlugins (bootstrap-registry-*.js:72)
deriveSessionChatType (session-chat-type-*.js:34)
hasBackingSession → reconcileTaskRecordForOperatorInspection (task-registry.maintenance-*.js)
getStatusSummary (status.summary-*.js:94)
statusCommand (status-*.js:275)

iterateBootstrapChannelPlugins appears to enumerate all bundled channel roots and sync-import each one to derive session chat-type, rather than honoring the disabled-in-config list (or lazy-loading only the channel that owns the session in question).

Why this matters

scripts/postinstall-bundled-plugins.mjs intentionally skips installing bundled extension deps:

Bundled extension runtime dependencies are extension-owned. Do not install every bundled extension dependency during core package install unless the legacy eager-install escape hatch is explicitly enabled; openclaw doctor --fix owns the repair path for extensions that are actually used.

So on any stock install, bundled plugins that the user hasn't touched have no node_modules/. That's fine — until status loads them anyway.

Workarounds

  • Set OPENCLAW_EAGER_BUNDLED_PLUGIN_DEPS=1 before install/upgrade (forces all deps).
  • Loop npm install --no-save across every dist/extensions/*/ with a package.json.
  • Use openclaw health instead of openclaw status.

Suggested fix

In deriveSessionChatType / iterateBootstrapChannelPlugins, either
(a) filter to channels that are actually referenced by the session being reconciled, or
(b) skip bundled plugins whose runtime deps aren't resolvable and emit a warning rather than throwing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions