openclaw - 💡(How to fix) Fix Bug: collectAlreadyStagedBundledRuntimeDepSpecs omits auto-loaded plugins, causing their deps to be pruned [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#75109Fetched 2026-05-01 05:38:05
View on GitHub
Comments
3
Participants
3
Timeline
5
Reactions
2
Timeline (top)
commented ×3closed ×1cross-referenced ×1

collectAlreadyStagedBundledRuntimeDepSpecs calls collectBundledPluginRuntimeDeps({ extensionsDir, config }) with the user config. This causes auto-loaded bundled plugins that are not explicitly present in config.plugins.entries (e.g. memory-core) to be excluded from the dep scan. As a result their deps (e.g. chokidar@^5.0.0) never appear in alreadyStagedSpecs, which prevents them from being retained when other plugins run ensureBundledPluginRuntimeDeps.

Root Cause

collectAlreadyStagedBundledRuntimeDepSpecs (in bundled-runtime-root-D11Fl_T4.js):

// CURRENT (buggy)
const { deps, pluginIds } = collectBundledPluginRuntimeDeps({
    extensionsDir,
    config: params.config  // excludes auto-loaded plugins not in config.plugins.entries
});

The purpose of this function is to find what's already physically installed in the install root — not what the current config activates. Passing config causes auto-loaded bundled plugins to be invisible here, breaking the retention chain for their deps.

Fix Action

Fix

Remove config from the collectBundledPluginRuntimeDeps call so all bundled plugins are scanned. The existing hasDependencySentinel([params.installRoot], dep) filter already ensures only physically-installed deps are returned, so scanning more candidate plugins is safe.

// FIXED
const { deps, pluginIds } = collectBundledPluginRuntimeDeps({
    extensionsDir
    // no config — scan all plugins; hasDependencySentinel filters to only installed ones
});

This was confirmed to stop the delete/reinstall cycle: with config omitted, chokidar appears in alreadyStagedSpecs, gets retained through other plugins' ensureBundledPluginRuntimeDeps runs, and is no longer pruned.

Code Example

// CURRENT (buggy)
const { deps, pluginIds } = collectBundledPluginRuntimeDeps({
    extensionsDir,
    config: params.config  // excludes auto-loaded plugins not in config.plugins.entries
});

---

// FIXED
const { deps, pluginIds } = collectBundledPluginRuntimeDeps({
    extensionsDir
    // no config — scan all plugins; hasDependencySentinel filters to only installed ones
});
RAW_BUFFERClick to expand / collapse

Summary

collectAlreadyStagedBundledRuntimeDepSpecs calls collectBundledPluginRuntimeDeps({ extensionsDir, config }) with the user config. This causes auto-loaded bundled plugins that are not explicitly present in config.plugins.entries (e.g. memory-core) to be excluded from the dep scan. As a result their deps (e.g. chokidar@^5.0.0) never appear in alreadyStagedSpecs, which prevents them from being retained when other plugins run ensureBundledPluginRuntimeDeps.

Reproduction

Environment: OpenClaw 2026.4.27, Linux, packaged install (/usr/lib/node_modules/openclaw), memory-core not in config.plugins.entries (auto-loaded).

Trigger: Any plugin's ensureBundledPluginRuntimeDeps runs after memory-core's own run has written the manifest with chokidar@^5.0.0.

Observed behavior:

  1. memory-core's ensureBundledPluginRuntimeDeps writes manifest including chokidar@^5.0.0.
  2. The next plugin's ensureBundledPluginRuntimeDeps runs. collectAlreadyStagedBundledRuntimeDepSpecs scans with configmemory-core excluded → chokidar not in alreadyStagedSpecs.
  3. retainSpecIfActive("chokidar@^5.0.0") returns false (not in retainedAllowedSpecs).
  4. pruneRetainedRuntimeDepsManifestSpecs sees chokidar in previousSpecs but not in nextSpecsdeletes chokidar from node_modules.
  5. Next openclaw doctor run reports chokidar@^5.0.0 (used by memory-core) as missing and reinstalls it.
  6. Cycle repeats on every gateway restart.

Verification: scanBundledPluginRuntimeDeps({ packageRoot, config }) (no pluginIds) returns 33 deps with chokidar: undefined. Same call with pluginIds: effectivePluginIds returns 19 deps with chokidar correctly present.

Root cause

collectAlreadyStagedBundledRuntimeDepSpecs (in bundled-runtime-root-D11Fl_T4.js):

// CURRENT (buggy)
const { deps, pluginIds } = collectBundledPluginRuntimeDeps({
    extensionsDir,
    config: params.config  // excludes auto-loaded plugins not in config.plugins.entries
});

The purpose of this function is to find what's already physically installed in the install root — not what the current config activates. Passing config causes auto-loaded bundled plugins to be invisible here, breaking the retention chain for their deps.

Fix

Remove config from the collectBundledPluginRuntimeDeps call so all bundled plugins are scanned. The existing hasDependencySentinel([params.installRoot], dep) filter already ensures only physically-installed deps are returned, so scanning more candidate plugins is safe.

// FIXED
const { deps, pluginIds } = collectBundledPluginRuntimeDeps({
    extensionsDir
    // no config — scan all plugins; hasDependencySentinel filters to only installed ones
});

This was confirmed to stop the delete/reinstall cycle: with config omitted, chokidar appears in alreadyStagedSpecs, gets retained through other plugins' ensureBundledPluginRuntimeDeps runs, and is no longer pruned.

Impact

  • File watching (config reload, memory updates) silently broken between gateway restarts and the next doctor run.
  • openclaw doctor always reports chokidar@^5.0.0 (used by memory-core) as missing on installs where memory-core is auto-loaded.
  • Unnecessary npm reinstall on every doctor run.

extent analysis

TL;DR

Remove the config parameter from the collectBundledPluginRuntimeDeps call to ensure all bundled plugins are scanned.

Guidance

  • Identify the collectAlreadyStagedBundledRuntimeDepSpecs function and modify it to remove the config parameter from the collectBundledPluginRuntimeDeps call.
  • Verify that the hasDependencySentinel filter is in place to ensure only physically-installed dependencies are returned.
  • Test the fix by running openclaw doctor and verifying that chokidar@^5.0.0 is no longer reported as missing.
  • Monitor the system for any recurrence of the delete/reinstall cycle.

Example

// FIXED
const { deps, pluginIds } = collectBundledPluginRuntimeDeps({
    extensionsDir
    // no config — scan all plugins; hasDependencySentinel filters to only installed ones
});

Notes

This fix assumes that the hasDependencySentinel filter is correctly implemented and will prevent unnecessary dependencies from being returned.

Recommendation

Apply the workaround by removing the config parameter from the collectBundledPluginRuntimeDeps call, as this has been confirmed to stop the delete/reinstall cycle.

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 Bug: collectAlreadyStagedBundledRuntimeDepSpecs omits auto-loaded plugins, causing their deps to be pruned [3 comments, 3 participants]