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 --version → 2026.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
npm install -g openclaw (fresh global install, do not set OPENCLAW_EAGER_BUNDLED_PLUGIN_DEPS=1)
- Configure a single channel (e.g. Telegram)
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.
Summary
openclaw statusfails at startup withCannot find module '@larksuiteoapi/node-sdk'(and then cascades tonostr-tools, etc.) even when those channels are markeddisabledinopenclaw plugins list. Other commands (openclaw health,openclaw doctor --fix) run cleanly against the same install.Environment
openclaw --version→2026.4.21 (f788c88)npm install -g openclaw→/Users/dinesh/.npm-global/lib/node_modules/openclawReproduction
npm install -g openclaw(fresh global install, do not setOPENCLAW_EAGER_BUNDLED_PLUGIN_DEPS=1)openclaw statusExpected
Status renders channel health for enabled channels. Disabled bundled plugins are not loaded.
Actual
After installing that dep manually,
statusadvances and crashes on the next bundled extension (nostr-toolsfor the nostr plugin), and so on.Stack (abbreviated)
iterateBootstrapChannelPluginsappears 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.mjsintentionally skips installing bundled extension deps:So on any stock install, bundled plugins that the user hasn't touched have no
node_modules/. That's fine — untilstatusloads them anyway.Workarounds
OPENCLAW_EAGER_BUNDLED_PLUGIN_DEPS=1before install/upgrade (forces all deps).npm install --no-saveacross everydist/extensions/*/with apackage.json.openclaw healthinstead ofopenclaw 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.