openclaw - 💡(How to fix) Fix Bundled extensions in dist/ break maintainer workflow with bind-mounted source [1 comments, 2 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#72083Fetched 2026-04-27 05:35:06
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
0
Author
Timeline (top)
closed ×1commented ×1

Since the v2026.4.x series, OpenClaw ships extensions pre-bundled in dist/extensions/<plugin>/ inside the Docker image, and the plugin loader prefers these bundles over TypeScript sources at extensions/<plugin>/src/. This silently breaks the workflow used by external maintainers who bind-mount their fork's extensions/<plugin>/ directory into a running container to test PR changes against a real installation, without rebuilding the image.

Error Message

distinctive log line (for example a params.log?.warn("[CHECK]") at the entry

Root Cause

External maintainers and contributors typically iterate on plugin code by:

  1. Editing extensions/<plugin>/src/*.ts in their fork checkout.
  2. Bind-mounting that directory into the upstream container.
  3. Restarting the container.
  4. Exercising the plugin path in a real production-like setup before pushing the PR.

This loop used to work because the loader resolved extensions/<plugin>/ first. Now contributors who try this still see the old code running, which leads to hours of confused debugging ("my log doesn't appear", "my fix doesn't work") before realizing the bundle is masking the bind-mount.

The workaround is to run pnpm build:docker locally and additionally bind-mount <your-fork>/dist/extensions/<plugin> to /app/dist/extensions/<plugin>. This works but adds significant friction to PR validation.

Fix Action

Fix / Workaround

The workaround is to run pnpm build:docker locally and additionally bind-mount <your-fork>/dist/extensions/<plugin> to /app/dist/extensions/<plugin>. This works but adds significant friction to PR validation.

Happy to test patches.

RAW_BUFFERClick to expand / collapse

Summary

Since the v2026.4.x series, OpenClaw ships extensions pre-bundled in dist/extensions/<plugin>/ inside the Docker image, and the plugin loader prefers these bundles over TypeScript sources at extensions/<plugin>/src/. This silently breaks the workflow used by external maintainers who bind-mount their fork's extensions/<plugin>/ directory into a running container to test PR changes against a real installation, without rebuilding the image.

Affected versions

  • Working: v2026.3.x and earlier — dist/extensions/ did not exist in the image, the bind-mounted TS sources were loaded directly via jiti.
  • Broken: v2026.4.x (verified on v2026.4.20-beta.x and v2026.4.24) — dist/extensions/<plugin>/*.js is loaded by the plugin discovery, the bind-mounted extensions/<plugin>/src/ is inert.

Reproduction

  1. Run ghcr.io/openclaw/openclaw:2026.4.24.
  2. Bind-mount <your-fork>/extensions/synology-chat:/app/extensions/synology-chat:ro.
  3. Modify <your-fork>/extensions/synology-chat/src/webhook-handler.ts to add a distinctive log line (for example a params.log?.warn("[CHECK]") at the entry of authorizeSynologyWebhook).
  4. Restart the gateway, send a webhook through, observe gateway logs.

Expected: the [CHECK] log appears in gateway logs.

Actual: the log does not appear; the corresponding code in /app/dist/channel-*.js (the bundled chunk) runs instead, with the version of the code that was packaged at image build time.

Why this matters

External maintainers and contributors typically iterate on plugin code by:

  1. Editing extensions/<plugin>/src/*.ts in their fork checkout.
  2. Bind-mounting that directory into the upstream container.
  3. Restarting the container.
  4. Exercising the plugin path in a real production-like setup before pushing the PR.

This loop used to work because the loader resolved extensions/<plugin>/ first. Now contributors who try this still see the old code running, which leads to hours of confused debugging ("my log doesn't appear", "my fix doesn't work") before realizing the bundle is masking the bind-mount.

The workaround is to run pnpm build:docker locally and additionally bind-mount <your-fork>/dist/extensions/<plugin> to /app/dist/extensions/<plugin>. This works but adds significant friction to PR validation.

Suggested directions

  • Document the new requirement explicitly in the contributor docs (the dist/extensions/ precedence and the pnpm build:docker step).
  • Or: in src/plugins/bundled-dir.ts, expose a clean opt-in (env var or config flag) for "prefer source over bundled, plugin by plugin" usable in production-like images.
  • Or: when a TS source is found at extensions/<plugin>/ AND a bundle exists at dist/extensions/<plugin>/, log a one-time warning at startup so the ambiguity is visible.

Environment

  • macOS arm64, Docker via OrbStack, image ghcr.io/openclaw/openclaw:2026.4.24.
  • Loader-related code: src/plugins/sdk-alias.ts (isBundledPluginDistModulePath), src/plugins/bundled-dir.ts.

Happy to test patches.

extent analysis

TL;DR

To fix the issue, contributors can run pnpm build:docker locally and bind-mount their fork's dist/extensions/<plugin> directory into the container.

Guidance

  • The problem arises from the plugin loader preferring pre-bundled extensions in dist/extensions/<plugin>/ over TypeScript sources at extensions/<plugin>/src/.
  • To verify the issue, follow the reproduction steps and check if the modified log line appears in the gateway logs.
  • As a temporary workaround, contributors can run pnpm build:docker and bind-mount their fork's dist/extensions/<plugin> directory to /app/dist/extensions/<plugin>.
  • To mitigate the issue, the contributor documentation should be updated to reflect the new requirement of running pnpm build:docker and bind-mounting the dist/extensions/<plugin> directory.

Example

No code snippet is provided as the issue is related to the build and deployment process rather than a specific code change.

Notes

The issue is specific to the v2026.4.x series, and the workaround may add friction to the PR validation process. A more permanent solution, such as exposing an opt-in for preferring source over bundled plugins, may be necessary.

Recommendation

Apply the workaround by running pnpm build:docker and bind-mounting the dist/extensions/<plugin> directory, as this is the most straightforward way to resolve the issue in the short term.

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 Bundled extensions in dist/ break maintainer workflow with bind-mounted source [1 comments, 2 participants]